Description
Solution
-
关键在于发现结论,以及简单的反演。
-
fib数列: f n = k f n − 1 + f n − 2 f_n=kf_{n-1}+f_{n-2} fn=kfn−1+fn−2满足 f x + y = f x − 1 f y + f x f y + 1 f_{x+y}=f_{x-1}f_y+f_xf_{y+1} fx+y=fx−1fy+fxfy+1,转移矩阵为 A n = [ [ f n − 1 , f n ] , [ f n , f n + 1 ] ] A^n=[[f_{n-1},f_n],[f_{n},f_{n+1}]] An=[[fn−1,fn],[fn,fn+1]] ,因此 g c d ( f i , f j ) = f g c d ( i , j ) gcd(f_i,f_j)=f_{gcd(i,j)} gcd(fi,fj)=fgcd(i,j)
-
推一推可以写出 ∑ i ∑ k ∣ i ∑ j ≤ i [ ( i , j ) = 1 ] [ j % k = − d ] \sum_i\sum_{k|i}\sum_{j\le i}[(i,j)=1][j\%k=-d] ∑i∑k∣i∑j≤i[(i,j)=1][j%k=−d]
-
不妨设 d > 0 d>0 d>0,那么必须有 ( k , j ) = 1 (k,j)=1 (k,j)=1。
-
有结论, [ k ∣ i ] ∑ j ≤ i [ ( i , j ) = 1 ] [ ( k , j ) = 1 ] [ j % k = d ] [k|i]\sum_{j\le i}[(i,j)=1][(k,j)=1][j\%k=d] [k∣i]∑j≤i[(i,j)=1][(k,j)=1][j%k=d]对于所有 [ ( d , k ) = 1 ] [(d,k)=1] [(d,k)=1]都相等,即 j j j在 % k \%k %k意义下是均匀分布的。
-
对于一类与整除相关的问题,联想到 ϕ ( n ) \phi(n) ϕ(n)的求法,我们可以类似的将 n n n拆成若干质因数的次幂考虑。
-
考虑对于某个 p p p, k = p x , i = p x + y k=p^x,i=p^{x+y} k=px,i=px+y,考虑 j j j在 m o d p x + y \mod p^{x+y} modpx+y下要同时满足上面的两个互质性质,然后再通过CRT合并,那么只需要证明在这个意义下是均匀的即可,那么这个就很显然是对的了。
-
后面的都很简单了。
-
两个小Tips:1.按照质因数次幂分别考虑,再合并。2.统计 f g c d f_{gcd} fgcd可以将贡献统计到 k ∣ g c d , h k k|gcd,h_k k∣gcd,hk的位置上,用反演可以简单求出 h h h。
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define maxn 1000005
#define ll long long
using namespace std;
int T,n,K,d,mo,i,j,k,c[maxn];
ll f[maxn],g[maxn];
int pri[maxn],tot,phi[maxn],bz[maxn],minp[maxn],mu[maxn];
void getpri(){
phi[1]=minp[1]=mu[1]=1;
for(i=2;i<maxn;i++){
if (!bz[i]) pri[++tot]=i,phi[i]=i-1,minp[i]=i,mu[i]=-1;
for(j=1;j<=tot&&i*pri[j]<maxn;j++){
bz[i*pri[j]]=1,minp[i*pri[j]]=pri[j];
if (i%pri[j]==0) {
phi[i*pri[j]]=phi[i]*pri[j];
break;
} else phi[i*pri[j]]=phi[i]*(pri[j]-1),mu[i*pri[j]]=-mu[i];
}
}
}
int main(){
freopen("ceshi.in","r",stdin);
// freopen("analyze.in","r",stdin);
// freopen("analyze.out","w",stdout);
scanf("%d",&T);
getpri();
while (T--){
scanf("%d%d%d%d",&n,&d,&K,&mo);
for(i=2,f[1]=1;i<=n;i++) f[i]=(f[i-1]*K+f[i-2])%mo;
if (!d){
ll cnt=0;
for(i=1;i<=n;i++) cnt+=phi[i];
printf("%lld\n",cnt%mo*f[1]%mo);
continue;
}
memset(g,0,sizeof(ll)*(n+1));
for(i=1;i<=n;i++) for(j=1;i*j<=n;j++) if (mu[j])
g[i*j]+=f[i]*mu[j];
for(i=1;i<=n;i++) g[i]%=mo;
c[1]=1;
for(i=2;i<=n;i++) c[i]=c[i/minp[i]]&(d%minp[i]>0);
ll ans=0;
for(i=1;i<=n;i++) if (c[i]){
ll sum=0;
for(j=i;j<=n;j+=i) sum+=phi[j];
(ans+=sum/phi[i]%mo*g[i])%=mo;
}
printf("%lld\n",(ans%mo+mo)%mo);
}
}


被折叠的 条评论
为什么被折叠?



