卧薪尝胆,厚积薄发。
Coprime Arrays
Date: Wed Dec 12 15:19:37 CST 2018
In Category:
NoCategory
Description:
对所有
$i\in[1,k]$
求出长为
$n$
的每个数在
$[1,i]$
的,所有数
$\gcd$
为
$1$
的数列个数。
$1\leqslant n,k\leqslant 2\times 10^6$
Solution:
其实让求的就是:
$$
b_k=\sum_{i_1=1}^k\sum_{i_2=1}^k\cdots\sum_{i_n=1}^k[\gcd(i_1,i_2,\dots,i_n)=1]
$$
反演得:
$$
b_k=\sum_{d=1}^k\mu(d)\lfloor\frac k d\rfloor^n
$$
如果只有单点询问的话显然可以除法分块优化到
$O(n\sqrt n)$
。
但是这个要对所有的
$[1,k]$
求,看了题解发现可以差分,也就是说
$d$
只对所有
$k\geqslant d$
产生贡献,而贡献每
$d$
个一段每段不相同,那就可以差分,每次在交界处更改,时间复杂度是
$O(k\ln k)$
的。
要预处理幂。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
int n,k;
#define MAXN 2000010
bool isprime[MAXN];
int prime[MAXN],tot = 0;
int mu[MAXN];
#define MOD 1000000007
int power(int a,int b)
{
int res = 1;
while(b > 0)
{
if(b & 1)res = 1ll * res * a % MOD;
a = 1ll * a * a % MOD;
b = b >> 1;
}
return res;
}
int diff[MAXN];
int pows[MAXN];
int main()
{
scanf("%d%d",&n,&k);
for(int i = 2;i <= k;++i)isprime[i] = true;
mu[1] = 1;
for(int i = 2;i <= k;++i)
{
if(isprime[i])
{
prime[++tot] = i;
mu[i] = -1;
}
for(int j = 1;j <= tot && i * prime[j] <= k;++j)
{
isprime[i * prime[j]] = false;
if(i % prime[j] == 0)
{
mu[i * prime[j]] = 0;
break;
}
else
{
mu[i * prime[j]] = -mu[i];
}
}
}
for(int i = 1;i <= k;++i)pows[i] = power(i,n);
for(int i = 1;i <= k;++i)
{
for(int j = i;j <= k;j += i)
{
diff[j] = ((diff[j] + mu[i] * (pows[j / i] - pows[j / i - 1] + MOD) % MOD) % MOD + MOD) % MOD;
}
}
int ans = 0;
for(int i = 1;i <= k;++i)
{
diff[i] = (diff[i] + diff[i - 1]) % MOD;
ans = (ans + (diff[i] ^ i)) % MOD;
}
cout << ans << endl;
return 0;
}
In tag:
数学-莫比乌斯反演
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡