【題解】[牛客網NOIP賽前集訓營-提高組(第一場)]B.數數字 線性DP
阿新 • • 發佈:2018-11-01
#include<cstdio> #include<cstring> typedef long long ll; #define _rep(i,a,b) for(int i=(a);i<=(b);i++) #define _for(i,a,b) for(int i=(a);i<(b);i++) int co[10][10]; ll pw[10][100],l,r,l1,r1,ans,g[2][3][2][2],f[2][3][60][38][27][22]; ll nozero(ll x) { if(x<=0)return 0; memset(f,0,sizeof(f)); int cr=0;f[0][1][0][0][0][0]=1; ll ret=0,val; for(;x;x/=10,cr^=1) { int bit=x%10; memset(f[cr^1],0,sizeof(f[cr])); _for(i,0,3)_for(n2,0,60)_for(n3,0,38)_for(n5,0,27)_for(n7,0,22)if(val=f[cr][i][n2][n3][n5][n7]) { ll q1=r1/pw[2][n2]/pw[3][n3]/pw[5][n5]/pw[7][n7]; ll p1=(l1-1)/pw[2][n2]/pw[3][n3]/pw[5][n5]/pw[7][n7]; if(q1>=1&&p1<=0)ret+=val; if(q1<=0)continue; _for(p,1,10) { int ni=(p>bit?2:(p==bit?i:0)); int c2=n2+co[p][2]; int c3=n3+co[p][3]; int c5=n5+co[p][5]; int c7=n7+co[p][7]; if(c2>=60||c3>=38||c5>=27||c7>=22)continue; f[cr^1][ni][c2][c3][c5][c7]+=val; } } } _for(i,0,2)_for(n2,0,60)_for(n3,0,38)_for(n5,0,27)_for(n7,0,22)if(val=f[cr][i][n2][n3][n5][n7]) { ll q1=r1/pw[2][n2]/pw[3][n3]/pw[5][n5]/pw[7][n7]; ll p1=(l1-1)/pw[2][n2]/pw[3][n3]/pw[5][n5]/pw[7][n7]; if(q1>=1&&p1<=0)ret+=val; } return ret; } ll zero(ll x) { if(l1)return 0;//如果含0乘積為0 memset(g,0,sizeof(g)); int cr=0;ll ret=0; g[0][1][0][0]=1; for(;x;x/=10,cr^=1) { int bit=x%10;//取出該位 memset(g[cr^1],0,sizeof(g[cr])); _for(i,0,3)_for(j,0,2)_for(hd,0,2)if(g[cr][i][j][hd]) { if(hd&&j)ret+=g[cr][i][j][hd]; _for(p,0,10) { int ni=(p>bit?2:(p==bit?i:0)); int nj=(j|(p==0)); int hdt=(p>0); g[cr^1][ni][nj][hdt]+=g[cr][i][j][hd]; } } } return ret+g[cr][0][1][1]+g[cr][1][1][1]; } ll calc(ll x) { return zero(x)+nozero(x); } int main() { //freopen("in.txt","r",stdin); _for(i,1,10) { _for(j,2,10) for(int k=i;k%j==0;k/=j) co[i][j]++;//預處理出i有多少個j因子 pw[i][0]=1; for(int j=1;j<=60;j++) pw[i][j]=pw[i][j-1]*i;//預處理出i的次冪 } scanf("%lld%lld%lld%lld",&l,&r,&l1,&r1); if(!l)ans+=(l1==0),l++; if(l<=r)ans+=calc(r)-calc(l-1); printf("%lld\n",ans); return 0; }
總結
線性DP好題,狀態定義是關鍵