首先容斥一下,变为求 [1,n] 有多少数在 P 进制下相邻位互质
然后就可以
fi,j=∑k=1P−1 [gcd(j,k)=1]fi−1,k=∑k=1P−1fi−1,k∑d|j,d|kμ(d)=∑d|jμ(d)∑dt≤P−1fi−1,dt
然后可以发现,已知 fi−1 的情况下, ∑dt≤P−1fi−1,dt 是可以 O(P⋅lnP) 求得的
然后通过枚举
d
,也是可以实现
所以总复杂度为 O(logRP⋅P⋅lnP)=O(PlogR2)
示例程序:
#include<cstdio>
#include<cstring>
#define cl(x,y) memset(x,y,sizeof(x))
typedef long long ll;
const int maxn=100005,N=maxn-5;
int tst,P;
ll L,R,f[70][maxn];
int p[maxn],mu[maxn];
bool vis[maxn];
void prepare(){
mu[1]=1;
for (int i=2;i<=N;i++){
if (!vis[i]) p[++p[0]]=i,mu[i]=-1;
for (int j=1;j<=p[0]&&i*p[j]<=N;j++){
vis[i*p[j]]=1;
if (i%p[j]==0) {mu[i*p[j]]=0;break;}
else mu[i*p[j]]=-mu[i];
}
}
}
int a[70];
int gcd(int x,int y){
return y==0?x:gcd(y,x%y);
}
ll dfs(int i,int j,bool b){
if (i==1) return 1;
if (!b&&f[i][j]) return f[i][j];
int Max=0;if (b) Max=a[i-1];else Max=P-1;
ll res=0;
for (int k=1;k<=Max;k++)
if (gcd(j,k)==1) res+=dfs(i-1,k,b&&(Max==k));
return res;
}
ll calc(ll x){
cl(a,0);ll N=x;
do a[++a[0]]=N%P,N/=P; while(N);
ll res=0;
for (int i=1;i<a[0];i++)
for (int j=1;j<P;j++) res+=dfs(i,j,0);
for (int j=1;j<=a[a[0]];j++) res+=dfs(a[0],j,j==a[a[0]]);
return res;
}
void DP(){
cl(a,0);ll N=R;
do a[++a[0]]=N%P,N/=P; while(N);
for (int i=1;i<=a[0];i++)
for (int j=0;j<P;j++) f[i][j]=0;
for (int j=1;j<P;j++) f[1][j]=1;
for (int i=2;i<=a[0];i++)
for (int d=1;d<P;d++){
ll g=0;
for (int k=d;k<P;k+=d) g+=f[i-1][k];
for (int j=d;j<P;j+=d) f[i][j]+=mu[d]*g;
}
}
int main(){
prepare();
scanf("%d",&tst);
while (tst--){
scanf("%lld%lld%d",&L,&R,&P);
DP();
printf("%lld\n",calc(R)-calc(L-1));
}
return 0;
}


789

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



