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 }
View Code

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 }
View Code

双倍经验:https://www.nowcoder.com/acm/contest/172/B

 

posted @ 2018-04-19 17:45  hehe_54321  阅读(190)  评论(0编辑  收藏  举报
AmazingCounters.com