51nod-1232: 完美数
【传送门:51nod-1232】
简要题意:
完美数定义:一个数能够被它每一位非零的数整除,例如:11,12,15,但13就不是完美数,因为13不能被3整除
给出T组询问,每组询问输入l,r,输出l到r中有多少个完美数
题解:
首先很容易想到只要当前数被每一位所有非零的数的lcm整除就好了
实际上最大的lcm只有2520,而且只能够构成48个不同lcm的值
那么就可以利用这个来节省空间了,将lcm离散编号
设f[i][j][k]为第i位已经填好数字后,当前构成的数%2520=j,且当前数位的数的lcm的离散编号为k
然后直接记忆化搜索就行了
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> using namespace std; typedef long long LL; LL f[21][3100][51]; int p[3100],Mod=2520; void pre() { int k=0;p[0]=0; for(int i=1;i<=Mod;i++) if(Mod%i==0) p[i]=++k; } int cnt[21],tot; int gcd(int a,int b) { if(a==0) return b; else return gcd(b%a,a); } int getd(int a,int b) { if(a==0) return b; if(b==0) return a; return a*b/gcd(a,b); } LL dfs(int tp,int x,int d1,int d2) { if(x==1) { if(d2==0) return 0; return d1%d2==0; } if(tp==0&&f[x][d1][p[d2]]!=-1) return f[x][d1][p[d2]]; if(tp==0) { f[x][d1][p[d2]]=0; for(int i=0;i<=9;i++) { if(i==0) f[x][d1][p[d2]]+=dfs(tp,x-1,(d1*10+i)%Mod,d2); else f[x][d1][p[d2]]+=dfs(tp,x-1,(d1*10+i)%Mod,getd(d2,i)); } return f[x][d1][p[d2]]; } else { LL ans=0; for(int i=0;i<=cnt[x-1];i++) { if(cnt[x-1]==0) ans+=dfs(tp,x-1,(d1*10+i)%Mod,d2); else if(i==0) ans+=dfs(tp^1,x-1,(d1*10+i)%Mod,d2); else if(i==cnt[x-1]) ans+=dfs(tp,x-1,(d1*10+i)%Mod,getd(d2,i)); else ans+=dfs(tp^1,x-1,(d1*10+i)%Mod,getd(d2,i)); } return ans; } } LL solve(LL x) { if(x==0) return 0; LL d=x;tot=0; while(d!=0){cnt[++tot]=d%10;d/=10;} LL ans=0; for(int i=0;i<=cnt[tot];i++) { if(i==0) ans+=dfs(0,tot,0,0); else if(i==cnt[tot]) ans+=dfs(1,tot,i,i); else ans+=dfs(0,tot,i,i); } return ans; } int main() { pre(); int T; scanf("%d",&T); memset(f,-1,sizeof(f)); while(T--) { LL l,r; scanf("%lld%lld",&l,&r); printf("%lld\n",solve(r)-solve(l-1)); } return 0; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚