题目概述
求 [L,R] 中有多少数在 P 进制下任意相邻位互质。
解题报告
肯定是数位DP,把转移方程表示出来:
所以当已知 f[i−1] 的时候,就可以用两次类似埃式筛的方法求出 f[i] 。效率 Plog2PlogPR=Plog2R 。
示例程序
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxl=60,maxp=1e5;
int te,P,mu[maxp+5],p[maxp+5];bool pri[maxp+5];
int a[maxl+5];LL L,R,f[maxl+5][maxp+5];
void Make()
{
pri[1]=true;mu[1]=1;
for (int i=2;i<=maxp;i++)
{
if (!pri[i]) p[++p[0]]=i,mu[i]=-1;
for (int j=1,t;j<=p[0]&&(t=i*p[j])<=maxp;j++)
{
pri[t]=true;mu[t]=-mu[i];
if (!(i%p[j])) {mu[t]=0;break;}
}
}
}
int gcd(int a,int b) {if (!b) return a;return gcd(b,a%b);}
LL Dfs(int i,int j,bool fl)
{
if (i==1) return 1;if (!fl&&f[i][j]) return f[i][j];
int MAX=0;if (fl) MAX=a[i-1]; else MAX=P-1;LL ans=0;
for (int k=1;k<=MAX;k++) if (gcd(j,k)==1) ans+=Dfs(i-1,k,fl&&k==MAX);
if (!fl) f[i][j]=ans;return ans;
}
inline LL Solve(LL x)
{
a[0]=0;do a[++a[0]]=x%P,x/=P; while (x);LL ans=0;
for (int i=1;i<a[0];i++)
for (int j=1;j<P;j++)
ans+=Dfs(i,j,false);
for (int j=1;j<=a[a[0]];j++) ans+=Dfs(a[0],j,j==a[a[0]]);
return ans;
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
for (Make(),scanf("%d",&te);te;te--)
{
scanf("%lld%lld%d",&L,&R,&P);
LL x=R;a[0]=0;do a[++a[0]]=x%P,x/=P; while (x);
for (int i=0;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 sum=0;for (int t=d;t<P;t+=d) sum+=f[i-1][t];
for (int t=d;t<P;t+=d) f[i][t]+=sum*mu[d];
}
printf("%lld\n",Solve(R)-Solve(L-1));
}
return 0;
}