一、题目
二、解法
设 f ( i ) f(i) f(i)为值域在 [ 1 , k ] [1,k] [1,k]的 n n n个数,最后的 gcd \gcd gcd为 i i i的方案数。
设
F
(
i
)
F(i)
F(i)为值域在
[
1
,
k
]
[1,k]
[1,k]的
n
n
n个数,最后
gcd
\gcd
gcd为
i
i
i的倍数的方案数。
F
(
i
)
=
∑
i
∣
d
f
(
d
)
=
(
k
i
)
n
F(i)=\sum_{i|d}f(d)=(\frac{k}{i})^n
F(i)=i∣d∑f(d)=(ik)n
f
(
i
)
=
∑
i
∣
d
μ
(
d
i
)
F
(
d
)
f(i)=\sum_{i|d}\mu(\frac{d}{i})F(d)
f(i)=i∣d∑μ(id)F(d)
f
(
1
)
=
∑
i
=
1
k
μ
(
i
)
F
(
i
)
=
∑
i
=
1
k
μ
(
i
)
(
k
i
)
n
f(1)=\sum_{i=1}^k\mu(i)F(i)=\sum_{i=1}^k\mu(i)(\frac{k}{i})^n
f(1)=i=1∑kμ(i)F(i)=i=1∑kμ(i)(ik)n上面的式子显然可以分块,但是不够快,由于异或的存在,我们必须处理出每一个
b
k
b_k
bk,这时我们就要考虑它的共性,可以考虑循环中每一个
i
i
i的贡献,把
k
k
k划分成若干段,每一段内的贡献是一样的(每一段
k
/
i
k/i
k/i一样),我们就可以打差分标记,注意要删除以前的标记,那么时间复杂度就是
O
(
n
log
n
)
O(n\log n)
O(nlogn)
#include <cstdio>
#include <iostream>
using namespace std;
#define int long long
const int M = 2000005;
const int jzm = 1e9+7;
int read()
{
int x=0,flag=1;
char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,k,ans,cnt,pw[M],p[M],b[M],vis[M],mu[M];
int qkpow(int a,int b)
{
int r=1;
while(b>0)
{
if(b&1) r=r*a%jzm;
a=a*a%jzm;
b>>=1;
}
return r;
}
void init(int n)
{
mu[1]=1;
for(int i=2;i<=n;i++)
{
if(!vis[i])
{
p[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt && i*p[j]<=n;j++)
{
vis[i*p[j]]=1;
if(i%p[j]==0) break;
mu[i*p[j]]=-mu[i];
}
}
}
signed main()
{
n=read();k=read();
init(k);
for(int i=1;i<=k;i++)
pw[i]=qkpow(i,n);
for(int i=1;i<=k;i++)
for(int j=1;j*i<=k;j++)
{
b[i*j]=(b[i*j]+mu[i]*pw[j])%jzm;
b[i*j]=(b[i*j]-mu[i]*pw[j-1])%jzm;
}
for(int i=1;i<=k;i++)
{
b[i]=((b[i]+b[i-1])%jzm+jzm)%jzm;
ans=(ans+(b[i]^i)%jzm)%jzm;
}
printf("%lld\n",ans);
}