bzoj 3679: 数字之积
注意到每个数位的质因子只会有2,3,5,7四种,所以分开统计,数位dp
此题卡空间,最好是写成循环,用滚动数组,我这里是卡了好久才过去的
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 typedef long long LL; 6 LL dp[55][37][19][19][19]; 7 LL d2[]={0,0,1,0,2,0,1,0,3,0}; 8 LL d3[]={0,0,0,1,0,0,1,0,0,2}; 9 LL d5[]={0,0,0,0,0,1,0,0,0,0}; 10 LL d7[]={0,0,0,0,0,0,0,1,0,0}; 11 LL g[30],glen; 12 LL dfs(LL pos,LL a,LL b,LL c,LL d,bool limit,bool pre0) 13 { 14 if(a<0||b<0||c<0||d<0) return 0; 15 if(!pos) return !pre0&&a==0&&b==0&&c==0&&d==0; 16 if(!limit&&!pre0&&dp[pos][a][b][c][d]!=-1) 17 return dp[pos][a][b][c][d]; 18 LL ed=limit?g[pos]:9,res=0,i; 19 for(i=1;i<=ed;i++) 20 res+=dfs(pos-1,a-d2[i],b-d3[i],c-d5[i],d-d7[i],limit&&i==g[pos],pre0&&i==0); 21 return limit||pre0?res:dp[pos][a][b][c][d]=res; 22 } 23 LL get(LL a,LL b,LL c,LL d) 24 { 25 LL ans=0,i; 26 for(i=1;i<=glen;i++) ans+=dfs(i,a,b,c,d,i==glen,1); 27 return ans; 28 } 29 LL n,L,R; 30 LL pw2[70],pw3[70],pw5[70],pw7[70]; 31 bool judge(LL a,LL b,LL c,LL d) 32 { 33 LL ans=1; 34 if(pw2[a]==-1||pw3[b]==-1||pw5[c]==-1||pw7[d]==-1) return 0; 35 ans*=pw2[a];if(ans>n) return 0; 36 ans*=pw3[b];if(ans>n) return 0; 37 ans*=pw5[c];if(ans>n) return 0; 38 ans*=pw7[d];if(ans>n) return 0; 39 return 1; 40 } 41 LL ans; 42 int main() 43 { 44 LL i,j,k,l; 45 memset(dp,-1,sizeof(dp)); 46 scanf("%lld%lld%lld",&n,&L,&R);L--;R--; 47 pw2[0]=pw3[0]=pw5[0]=pw7[0]=1; 48 for(i=1;i<=60;i++) 49 { 50 if(pw2[i-1]==-1) pw2[i]=-1; 51 else pw2[i]=pw2[i-1]*2; 52 if(pw3[i-1]==-1) pw3[i]=-1; 53 else pw3[i]=pw3[i-1]*3; 54 if(pw5[i-1]==-1) pw5[i]=-1; 55 else pw5[i]=pw5[i-1]*5; 56 if(pw7[i-1]==-1) pw7[i]=-1; 57 else pw7[i]=pw7[i-1]*7; 58 if(pw2[i]>n) pw2[i]=-1; 59 if(pw3[i]>n) pw3[i]=-1; 60 if(pw5[i]>n) pw5[i]=-1; 61 if(pw7[i]>n) pw7[i]=-1; 62 } 63 for(glen=0;R;R/=10) g[++glen]=R%10; 64 for(i=0;i<=55;i++) 65 for(j=0;j<=37;j++) 66 for(k=0;k<=19;k++) 67 for(l=0;l<=19;l++) 68 { 69 if(!judge(i,j,k,l)) continue; 70 ans+=get(i,j,k,l); 71 } 72 for(glen=0;L;L/=10) g[++glen]=L%10; 73 for(i=0;i<=55;i++) 74 for(j=0;j<=37;j++) 75 for(k=0;k<=19;k++) 76 for(l=0;l<=19;l++) 77 { 78 if(!judge(i,j,k,l)) continue; 79 ans-=get(i,j,k,l); 80 } 81 printf("%lld",ans); 82 return 0; 83 }
20180928
用循环重新写了一遍
错误记录:没有判138行"!has0[p+1]",无限WA
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 #define fi first 7 #define se second 8 #define mp make_pair 9 #define pb push_back 10 typedef long long ll; 11 typedef unsigned long long ull; 12 typedef pair<int,int> pii; 13 ll g[22]; 14 namespace s1 15 { 16 17 ll an[22][2][2];//an[i位][是否含0(含前导0)][第i位是否为(前导)0] 18 void pre() 19 { 20 ll i; 21 an[0][0][1]=1; 22 for(i=1;i<=19;i++) 23 { 24 an[i][1][0]=9*(an[i-1][1][0]+an[i-1][1][1]); 25 an[i][1][1]=an[i-1][1][0]+an[i-1][1][1]+an[i-1][0][0]+an[i-1][0][1]; 26 an[i][0][0]=9*(an[i-1][0][0]+an[i-1][0][1]); 27 an[i][0][1]=0; 28 } 29 } 30 ll calc()//[1,g)之间有多少个数数位中有0 31 { 32 ll i,ans=0; 33 for(i=1;i<g[0];i++)//g[0]位取0 34 { 35 ans+=an[i][1][0]; 36 } 37 if(g[g[0]]!=0)//g[0]位取1~(g[g[0]]-1) 38 ans+=(g[g[0]]-1)*(an[g[0]-1][1][0]+an[g[0]-1][1][1]); 39 bool ok=0; 40 for(i=g[0]-1;i>=1;i--)//i位之前与原数相同,i位小于原数,i位以后任意取 41 { 42 if(ok) ans+=g[i]*(an[i-1][0][0]+an[i-1][0][1]+an[i-1][1][0]+an[i-1][1][1]); 43 else if(g[i]!=0) 44 { 45 ans+=(g[i]-1)*(an[i-1][1][0]+an[i-1][1][1]);//当前位取1~g[i] 46 ans+=an[i-1][0][0]+an[i-1][0][1]+an[i-1][1][0]+an[i-1][1][1];//当前位取0 47 } 48 ok|=(g[i]==0); 49 } 50 //if(ok) ans++; 51 return ans; 52 } 53 54 55 } 56 /* 57 xx2:; 58 int main() 59 { 60 s1::pre(); 61 while(1) 62 { 63 ll t;scanf("%lld",&t); 64 for(g[0]=0;t;t/=10) g[++g[0]]=t%10; 65 printf("%lld\n",s1::calc()); 66 } 67 return 0; 68 } 69 */ 70 ll d2[]={0,0,1,0,2,0,1,0,3,0}; 71 ll d3[]={0,0,0,1,0,0,1,0,0,2}; 72 ll d5[]={0,0,0,0,0,1,0,0,0,0}; 73 ll d7[]={0,0,0,0,0,0,0,1,0,0}; 74 ll s2[22],s3[22],s5[22],s7[22]; 75 bool has0[22]; 76 ll an[2][56][38][20][20]; 77 //an[i位][p2][p3][p5][p7] 78 ll calc(ll R,ll R1)//数[0,R],数位积[0,R1] 79 { 80 if(R<0||R1<0) return 0; 81 if(R==0) return 1; 82 ll ans=1;//数0 83 R++; 84 for(g[0]=0;R;R/=10) g[++g[0]]=R%10; 85 ans+=s1::calc();//数位积0 86 ll p,i,j,k,l,nn,pw1,pw2,pw3,pw4; 87 /* 88 for(t=1,i=1;i<=18;t=t*10+1,i++)//数位积1 89 if(t<=R) 90 ans++; 91 */ 92 //此处之后只需要统计数[1,R),数位积[1,R1] 93 //处理[1,R) 94 s2[g[0]+1]=s3[g[0]+1]=s5[g[0]+1]=s7[g[0]+1]=0;has0[g[0]+1]=0; 95 for(i=g[0];i>=1;i--) 96 { 97 s2[i]=s2[i+1]+d2[g[i]]; 98 s3[i]=s3[i+1]+d3[g[i]]; 99 s5[i]=s5[i+1]+d5[g[i]]; 100 s7[i]=s7[i+1]+d7[g[i]]; 101 has0[i]=has0[i+1]||(g[i]==0); 102 } 103 ll lst=1,now=0; 104 memset(an[now],0,sizeof(an[now])); 105 an[now][0][0][0][0]=1; 106 for(p=1;p<=g[0];p++) 107 { 108 swap(lst,now); 109 memset(an[now],0,sizeof(an[now])); 110 for(i=0,pw1=1;pw1<=R1&&i<56;i++,pw1*=2) 111 for(j=0,pw2=pw1;pw2<=R1&&j<38;j++,pw2*=3) 112 for(k=0,pw3=pw2;pw3<=R1&&k<20;k++,pw3*=5) 113 for(l=0,pw4=pw3;pw4<=R1&&l<20;l++,pw4*=7) 114 { 115 for(nn=1;nn<=9;nn++) 116 if(i>=d2[nn]&&j>=d3[nn]&&k>=d5[nn]&&l>=d7[nn]) 117 an[now][i][j][k][l]+=an[lst][i-d2[nn]][j-d3[nn]][k-d5[nn]][l-d7[nn]]; 118 } 119 if(p<g[0]) 120 { 121 for(i=0,pw1=1;pw1<=R1&&i<56;i++,pw1*=2) 122 for(j=0,pw2=pw1;pw2<=R1&&j<38;j++,pw2*=3) 123 124 for(k=0,pw3=pw2;pw3<=R1&&k<20;k++,pw3*=5) 125 for(l=0,pw4=pw3;pw4<=R1&&l<20;l++,pw4*=7) 126 ans+=an[now][i][j][k][l]; 127 } 128 if(p==g[0]) 129 { 130 for(i=0,pw1=1;pw1<=R1&&i<56;i++,pw1*=2) 131 for(j=0,pw2=pw1;pw2<=R1&&j<38;j++,pw2*=3) 132 for(k=0,pw3=pw2;pw3<=R1&&k<20;k++,pw3*=5) 133 for(l=0,pw4=pw3;pw4<=R1&&l<20;l++,pw4*=7) 134 for(nn=1;nn<g[p];nn++) 135 if(i>=d2[nn]&&j>=d3[nn]&&k>=d5[nn]&&l>=d7[nn]) 136 ans+=an[lst][i-d2[nn]][j-d3[nn]][k-d5[nn]][l-d7[nn]]; 137 } 138 if(p<g[0]&&!has0[p+1]) 139 { 140 for(i=0,pw1=1;pw1<=R1&&i<56;i++,pw1*=2) 141 for(j=0,pw2=pw1;pw2<=R1&&j<38;j++,pw2*=3) 142 for(k=0,pw3=pw2;pw3<=R1&&k<20;k++,pw3*=5) 143 for(l=0,pw4=pw3;pw4<=R1&&l<20;l++,pw4*=7) 144 for(nn=1;nn<g[p];nn++) 145 if(i>=s2[p+1]+d2[nn]&&j>=s3[p+1]+d3[nn] 146 &&k>=s5[p+1]+d5[nn]&&l>=s7[p+1]+d7[nn]) 147 ans+=an[lst][i-s2[p+1]-d2[nn]][j-s3[p+1]-d3[nn]] 148 [k-s5[p+1]-d5[nn]][l-s7[p+1]-d7[nn]]; 149 } 150 } 151 return ans; 152 } 153 int main() 154 { 155 s1::pre(); 156 /* 157 while(1) 158 { 159 ll t1,t2; 160 scanf("%lld%lld",&t1,&t2); 161 printf("%lld\n",calc(t1,t2)); 162 }*/ 163 ll L,R,L1,R1; 164 //scanf("%lld%lld%lld%lld",&L,&R,&L1,&R1); 165 scanf("%lld%lld%lld",&R1,&L,&R); 166 R--;L1=1; 167 printf("%lld",calc(R,R1)-calc(R,L1-1)-calc(L-1,R1)+calc(L-1,L1-1)); 168 return 0; 169 }
双倍经验:https://www.nowcoder.com/acm/contest/172/B