您的位置:首页 > 其它

[莫比乌斯反演+数位DP]计蒜客 阿里云秘钥池

2017-12-10 20:41 274 查看


f[i][j]=∑k=1P−1f[i−1][k]∗e(gcd(j,k))

f[i][j]=∑k=1P−1f[i−1][k]∑d|j,d|kμ(d)

f[i][j]=∑d|jμ(d)∗∑k=1⌊p−1d⌋f[i−1][kd]

然后就数位DP一下

#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
#define N 100013
int T,P,mu
,prim
,c[70];
char p
;
ll l,r,sum,f[70]
;
void pre(void){
ll t;mu[1]=1;
for(int i=2;i<=N;++i){
if(!p[i])prim[++prim[0]]=i,mu[i]=-1;
for(int j=1;j<=prim[0]&&(t=1ll*i*prim[j])<=100000;++j){
p[t]=1;
if(i%prim[j]==0){
mu[t]=0;break;
}
mu[t]=-mu[i];
}
}
return ;
}
int gcd(int a,int b){
return a%b==0?b:gcd(b,a%b);
}
ll calc(ll x){
ll sum=0,a=x;
int tot=0;
while(a)c[++tot]=a%P,a/=P;
for(int i=tot;i;--i){
for(int j=1;j<c[i];++j)
if(i==tot||(gcd(j,c[i+1])==1))
sum+=f[i][j];
if(c[i]==0)break;
if(i!=tot&&gcd(c[i],c[i+1])!=1)break;
}
for(int i=tot-1;i;--i)
for(int j=1;j<P;++j)
sum+=f[i][j];
return sum;
}
int main(void){
register int i,j,k,len;
ll x;
pre(),scanf("%d",&T);
while(T--){
scanf("%lld%lld%d",&l,&r,&P);
x=r+1,len=0;while(x)x/=P,++len;
for(i=1;i<P;++i)f[1][i]=1;
for(i=2;i<=len;++i){
for(j=1;j<P;++j)f[i][j]=0;
for(j=1;j<P;++j){
sum=0;
for(k=j;k<P;k+=j)
sum+=f[i-1][k];
for(k=j;k<P;k+=j)
f[i][k]+=mu[j]*sum;
}
}
printf("%lld\n",calc(r+1)-calc(l));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: