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

题面在这里

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

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

fi,j=k=1P1 [gcd(j,k)=1]fi1,k=k=1P1fi1,kd|j,d|kμ(d)=d|jμ(d)dtP1fi1,dt

然后可以发现,已知 fi1 的情况下, dtP1fi1,dt 是可以 O(PlnP) 求得的

然后通过枚举 d ,也是可以实现O(PlnP)的转移

所以总复杂度为 O(logRPPlnP)=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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值