SCOI2013 day2 数数(count)

 

好吧,这是我两天里唯一考试时AC的题目…………

明显的按位DP,设sum1[i][lim][zero]表示在第i位,是否顶着上界,是否有前导零的所有数的前缀串之和(如12345的前缀串之和为12345+1234+123+12+1),sum2[i][lim][zero]记录的是所求的和,num[i][lim][zero]表示该状态下数的个数。那么转移很明显了:sum1[i]=now*tms[i]*num[i-1]+sum1[i-1],sum2[i]=sum2[i-1]+now*tms[i]*num[i-1]+sum1[i-1]*!(zero&&(now==0));(now为当前这一位,tms[i]=b^i+b^(i-1)+...+b^0,lim和zero略去,因为和普通按位DP一样)

当然,写出方程以后能得50分,剩下的50分因为进制数太大,需要优化转移。可以发现状态记录中不包括当前位是什么,也就是说不必枚举当前位,只需分情况讨论后(如上界,当前位为0),每种情况处理一次,然后用等差数列求和之类的东西推出该情况的所有部分就行了。

ps 记忆化要爆栈,需要想办法解决。

总之就一道水题…………没什么思维难度的……………我这种弱菜也就只做的起这种题了………………

代码,求大神轻虐!!(注释掉的那一段是没有优化转移的):

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 #define inc(a,b) a+=b,a=a>=MOD?a-MOD:a
  7 const int MOD=20130427;
  8 const int MAXN=100010;
  9 
 10 struct Ans
 11 {
 12     int num,sum1,sum2;
 13     Ans() {sum1=sum2=num=0;}
 14     Ans(int num,int sum1,int sum2):num(num),sum1(sum1),sum2(sum2) {}
 15 }dp[MAXN][2][2];
 16 
 17 bool dped[MAXN][2][2];
 18 int tms[MAXN],num[MAXN],n,ans1,ans2,B;
 19 
 20 //srO __TY Orz
 21 Ans fdp(int now,int flag,int lim)
 22 {
 23     if (now<0 && flag) return Ans(0,0,0);
 24     if (now<0) return Ans(1,0,0);
 25     if (dped[now][flag][lim])
 26         return dp[now][flag][lim];
 27     dped[now][flag][lim]=1;
 28     int up=lim?num[now]:B-1;
 29     Ans &ret=dp[now][flag][lim],cur;
 30     dp[now][flag][lim]=Ans();
 31     /*for (int i=0;i<=up;++i)
 32     {
 33         cur=fdp(now-1,flag&&(i==0),lim&&i==up);
 34         inc(ret.num,cur.num);
 35         ret.sum1=((long long)ret.sum1+cur.sum1+(long long)i*cur.num*tms[now]%MOD)%MOD;
 36         ret.sum2=((long long)ret.sum2+cur.sum2+(long long)i*cur.num*tms[now]%MOD+(!(flag&&(i==0)))*cur.sum1)%MOD;
 37     }*/
 38     cur=fdp(now-1,flag,lim&&(up==0));
 39     inc(ret.num,cur.num);
 40     inc(ret.sum1,cur.sum1);
 41     inc(ret.sum2,cur.sum2);
 42     if (!flag) inc(ret.sum2,cur.sum1);
 43     if (up>0)
 44     {
 45         cur=fdp(now-1,0,lim);
 46         inc(ret.num,cur.num);
 47         ret.sum1=((long long)ret.sum1+cur.sum1+(long long)up*cur.num%MOD*tms[now]%MOD)%MOD;
 48         ret.sum2=((long long)ret.sum2+cur.sum2+(long long)up*cur.num%MOD*tms[now]%MOD+cur.sum1)%MOD;
 49         if (up>1)
 50         {
 51             cur=fdp(now-1,0,0);
 52             ret.num=((long long)ret.num+(long long)cur.num*(up-1)%MOD)%MOD;
 53             ret.sum1=((long long)ret.sum1+(long long)cur.sum1*(up-1)%MOD)%MOD;
 54             ret.sum1=((long long)ret.sum1+((((long long)up*(up-1)>>1)%MOD*cur.num%MOD)*tms[now])%MOD)%MOD;
 55             ret.sum2=((long long)ret.sum2+(long long)cur.sum2*(up-1)%MOD)%MOD;
 56             ret.sum2=((long long)ret.sum2+((((long long)up*(up-1)>>1)%MOD*cur.num%MOD)*tms[now])%MOD)%MOD;
 57             ret.sum2=((long long)ret.sum2+(long long)cur.sum1*(up-1)%MOD)%MOD;
 58         }
 59     }
 60     return dp[now][flag][lim];
 61 }
 62 
 63 //srO __TY Orz
 64 int main()
 65 {
 66     freopen("count.in","r",stdin);
 67     freopen("count.out","w",stdout);
 68     tms[0]=1;
 69     scanf("%d",&B);
 70     for (int i=1;i<MAXN;++i)
 71         tms[i]=((long long)tms[i-1]*B+1)%MOD;
 72     scanf("%d",&n);
 73     for (int i=n-1;i>=0;--i)
 74         scanf("%d",&num[i]);
 75     while (!num[n-1] && n>1) --n;
 76     if (!(num[0]==0 && n==1))
 77     {
 78         --num[0];
 79         int x=0;
 80         while (num[x]<0)
 81         {
 82             num[x]+=B;
 83             --num[x+1];
 84             ++x;
 85         }
 86     }
 87     while (!num[n-1]) --n;
 88     for (int i=0;i<n;++i)
 89     {
 90         fdp(i,1,1);
 91         fdp(i,1,0);
 92         fdp(i,0,1);
 93         fdp(i,0,0);
 94     }
 95     ans1=fdp(n-1,1,1).sum2;
 96     memset(dped,0,sizeof(dped));
 97     scanf("%d",&n);
 98     for (int i=n-1;i>=0;--i)
 99         scanf("%d",&num[i]);
100     for (int i=0;i<n;++i)
101     {
102         fdp(i,1,1);
103         fdp(i,1,0);
104         fdp(i,0,1);
105         fdp(i,0,0);
106     }
107     ans2=fdp(n-1,1,1).sum2;
108     printf("%d\n",ans2-ans1<0?ans2-ans1+MOD:ans2-ans1);
109     return 0;
110 }
View Code
posted on 2013-06-01 16:39  stickjitb  阅读(529)  评论(2编辑  收藏  举报