您的位置:首页 > 其它

【莫比乌斯反演+数位DP】2017 计蒜之道 复赛 A.阿里云秘钥池

2017-12-11 06:56 393 查看
题面在这里

首先容斥一下,变为求[1,n]有多少数在P进制下相邻位互质

然后就可以DP了:fi,j表示前i位,最高位上是j的方案数

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(P⋅lnP)的转移

所以总复杂度为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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: