zoukankan      html  css  js  c++  java
  • 数位DP复习小结

    转载请注明原文地址http://www.cnblogs.com/LadyLex/p/8490222.html 

    之前学数位dp的时候底子没打扎实

    虚的要死

    这次正好有时间……刷了刷之前没做的题目

    感觉自己脑洞不太够……比较经典的题或者见过的类似模型就能自己推出来,但是没有见过的模型就虚的要死(比如二进制数位DP)

    感谢WQ的帮助,让我对数位DP的理解逐渐加深

    那么我们总结一下这次做的题目……

    bzoj4521

      记忆化搜索即可,水爆

     1 #include <cstring>
     2 #include <cstdio>
     3 using namespace std;
     4 #define RG register
     5 #define LL long long
     6 int bin[15],cnt;
     7 LL poww[15],f[12][10][3][3][2][2];
     8 inline int min(int a,int b){return a<b?a:b;}
     9 inline int max(int a,int b){return a>b?a:b;}
    10 inline LL dfs(int st,int pre,int comb,int maxcomb,bool have8,bool have4,bool limit)
    11 {
    12     if(st==0)return maxcomb==3;
    13     if(!limit&&f[st][pre][comb][maxcomb][have8][have4]!=-1)
    14         return f[st][pre][comb][maxcomb][have8][have4];
    15     LL ret=0;
    16     RG int i,tmp,lim=(limit)?bin[st]:10;
    17     for(i=0;i<lim;++i)
    18     {
    19         tmp=min((pre==i)?comb+1:1,3);
    20         if(i==4)
    21         {
    22             if(!have8)ret+=dfs(st-1,i,tmp,max(tmp,maxcomb),0,1,0);
    23         }
    24         else if(i==8)
    25         {
    26             if(!have4)ret+=dfs(st-1,i,tmp,max(tmp,maxcomb),1,0,0);
    27         }
    28         else ret+=dfs(st-1,i,tmp,max(tmp,maxcomb),have8,have4,0);
    29     }
    30     if(limit)
    31     {
    32         tmp=min((pre==i)?comb+1:1,3);
    33         if(i==4)
    34         {
    35             if(!have8)ret+=dfs(st-1,i,tmp,max(tmp,maxcomb),0,1,1);
    36         }
    37         else if(i==8)
    38         {
    39             if(!have4)ret+=dfs(st-1,i,tmp,max(tmp,maxcomb),1,0,1);
    40         }
    41         else ret+=dfs(st-1,i,tmp,max(tmp,maxcomb),have8,have4,1);
    42     }
    43     if(!limit)f[st][pre][comb][maxcomb][have8][have4]=ret;
    44     return ret;
    45 }
    46 inline LL calc(LL len)
    47 {
    48     LL ret=0;cnt=0;
    49     while(len)bin[++cnt]=len%10,len/=10;
    50     for(RG int i=1;i<bin[11];++i)ret+=dfs(10,i,1,1,i==8,i==4,0);
    51     return ret+dfs(10,bin[11],1,1,bin[11]==8,bin[11]==4,1);
    52 }
    53 int main()
    54 {
    55     LL l,r,ans;RG int i;
    56     for(poww[0]=i=1;i<=12;++i)poww[i]=poww[i-1]*9;
    57     scanf("%lld%lld",&l,&r);
    58     memset(f,-1,sizeof(f)),ans=calc(r);
    59     if(l>1e10)ans-=calc(l-1);
    60     printf("%lld
    ",ans);
    61 }
    BZOJ4521

    bzoj4029

      假装他是数位dp的小模拟

     1 #include <cstdio>
     2 #include <cstring>
     3 using namespace std;
     4 #define RG register
     5 #define LL long long
     6 int br[12],bl[12],lr,ll,_10[12];
     7 int main()
     8 {
     9     RG int pos,i,j,l,r,tmp,t,ans;
    10     scanf("%d",&t);
    11     for(_10[1]=1,i=2;i<=10;++i)_10[i]=_10[i-1]*10;
    12     while(t--)
    13     {
    14         scanf("%d%d",&l,&r),--l;
    15         ll=lr=0;
    16         tmp=r;while(tmp)br[++lr]=tmp%10,tmp/=10;
    17         tmp=l;while(tmp)bl[++ll]=tmp%10,tmp/=10;
    18         if(lr!=ll)
    19         {
    20             if(l<5*_10[ll])ans=5*_10[ll];
    21             else if(5*_10[ll+1]<=r)ans=5*_10[ll+1];
    22             else if(bl[ll]==9)ans=_10[ll+1];
    23             else ans=_10[ll]*(bl[ll]+1);
    24         }
    25         else
    26         {
    27             pos=ll;ans=0;
    28             while(bl[pos]==br[pos]&&pos)ans=ans*10+bl[pos],--pos;
    29             if(pos)
    30             {
    31                 if(bl[pos]<5&&5<=br[pos])ans=(ans*10+5)* _10[pos];
    32                 else ans=(ans*10+bl[pos]+1)* _10[pos];
    33             }
    34         }
    35         printf("%d
    ",ans);
    36     }
    37 }
    BZOJ4029

    bzoj3209

      从低位往高位DP,带个组合数乱搞,比较水,没有打

    bzoj3329

      两边同时异或一下x,然后由于异或是不进位的加法,所以发现性质是没有相邻的1,dp即可

     1 #include <cstring>
     2 #include <cstdio>
     3 using namespace std;
     4 #define mod 1000000007
     5 #define RG register 
     6 #define LL long long
     7 namespace work1
     8 {
     9     LL f[64][2];int bin[64],len;
    10     inline void init()
    11     {
    12         f[1][0]=1,f[1][1]=1;
    13         for(RG int i=2;i<=62;++i)
    14             f[i][0]=f[i-1][0]+f[i-1][1],f[i][1]=f[i-1][0];
    15     }
    16     inline LL dfs(int st,int pre,bool lim)
    17     {
    18         if(st==0)return 1;
    19         if(!lim)return pre?f[st][0]:f[st][0]+f[st][1];
    20         if(bin[st])
    21             return pre?dfs(st-1,0,0):(dfs(st-1,0,0)+dfs(st-1,1,1));
    22         return dfs(st-1,0,1);
    23     }
    24     inline LL work(LL n)
    25     {
    26         if(!n)return 0;
    27         len=0;while(n)bin[++len]=n&1,n>>=1;
    28         return dfs(len-1,0,0)+dfs(len-1,1,1)-1;
    29     }
    30 }
    31 namespace work2
    32 {
    33     struct matrix
    34     {
    35         int a[4][4];
    36         inline void clear(){memset(a,0,sizeof(a));}
    37         inline void init(){memset(a,0,sizeof(a));for(RG int i=0;i<4;++i)a[i][i]=1;}
    38         inline matrix operator * (const matrix &b)const
    39         {
    40             RG int i,j,k;
    41             matrix c;c.clear();
    42             for(i=0;i<4;++i)
    43                 for(k=0;k<4;++k)if(a[i][k])
    44                     for(j=0;j<4;++j)if(b.a[k][j])
    45                         c.a[i][j]=(c.a[i][j]+(LL)a[i][k]*b.a[k][j])%mod;
    46             return c;
    47         }
    48         inline void print()
    49         {
    50             for(RG int i=0;i<4;++i,printf("
    "))
    51                 for(RG int j=0;j<4;++j)
    52                     printf("%d ",a[i][j]);
    53         }
    54     }d,t;
    55     inline void init()
    56     {
    57         d.clear(),d.a[0][0]=d.a[0][1]=d.a[0][2]=d.a[1][0]=d.a[1][3]=1;
    58     }
    59     inline matrix quick_mod(matrix di,LL mi)
    60     {
    61         matrix ret;ret.init();
    62         for(;mi;mi>>=1,di=di*di)if(mi&1)ret=ret*di;
    63         return ret;
    64     }
    65     inline int work(LL n)
    66     {
    67         t.clear(),t.a[0][0]=t.a[0][1]=1,t=t*quick_mod(d,n);
    68         return t.a[0][0];
    69     }
    70 }
    71 int main()
    72 {
    73     RG int i,j,t;LL n;
    74     scanf("%d",&t);
    75     work1::init(),work2::init();
    76     while(t--)
    77         scanf("%lld",&n),printf("%lld
    %d
    ",work1::work(n),work2::work(n));
    78 }
    BZOJ3329

    bzoj1799

      打表发现数位之和很少,枚举数位之和,但是我没想到dp的定义……

      然后看了一下题解的数组定义,难度适中吧……没有那么难,但是自己还是没想出来

      那个维护当前值然后每次cur=cur×10+i的很巧妙,没想出来……

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 #define RG register
     6 #define LL long long
     7 int bin[20];
     8 inline int min(int a,int b){return a<b?a:b;}
     9 inline int max(int a,int b){return a>b?a:b;}
    10 int mod,mark[20][163][163][2];
    11 LL f[20][163][163][2];
    12 inline LL dfs(int st,int sum,int cur,bool lim)
    13 {    
    14     if(st==0)return cur==0&&sum==0;
    15     if(mark[st][sum][cur][lim]==mod)return f[st][sum][cur][lim];
    16     mark[st][sum][cur][lim]=mod;LL ret=0;
    17     RG int i,l=max(0,sum-(st-1)*9 ),r=min( sum+1,(lim?bin[st]:10) );
    18     for(i=l;i<r;++i)ret+=dfs(st-1,sum-i,(cur*10+i)%mod,0);
    19     if(lim && sum>=bin[st] )
    20         ret+=dfs(st-1,sum-bin[st],(cur*10+bin[st])%mod,1);
    21     return f[st][sum][cur][lim]=ret;
    22 }
    23 inline LL calc(LL n)
    24 {
    25     RG int cnt=0;LL ret=0;
    26     while(n)bin[++cnt]=n%10,n/=10;
    27     memset(mark,0,sizeof(mark));
    28     for(mod=1;mod<=162;++mod)ret+=dfs(cnt,mod,0,1);
    29     return ret;
    30 }
    31 int main()
    32 {
    33     RG int i,j;LL l,r;
    34     scanf("%lld%lld",&l,&r);
    35     printf("%lld
    ",calc(r)-calc(l-1));
    36 }
    BZOJ1799

    bzoj1183+bzoj2713

      这个和之前那个淘金很像……先预处理乘积,后面那个我一开始一直在想像上面1799的搞法带着乘积走

      然后发现不行,最后得到了提示,对于每一个乘积x,我去查询l/x,r/x区间内乘积为x的数就行了

      这个转化和之前数学上那个gcd很像:d|ij <==> d/gcd(i,d) | j

      啊我好蠢啊

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <cstdlib>
     5 using namespace std;
     6 #define RG register
     7 #define LL long long
     8 #define L 440000
     9 #define UL 44000
    10 int bin[20],len,cnt;
    11 LL _9[20],mul[L],f[20][UL],l,r;
    12 inline void dfs1(int st,int pre,LL multi)
    13 {
    14     mul[++cnt]=multi;
    15     if(st==11)return;
    16     for(RG int i=pre;i<10;++i)
    17         if(multi*i<=r)dfs1(st+1,i,multi*i);
    18 }
    19 inline int id(LL val){return lower_bound(mul+1,mul+cnt+1,val)-mul;}
    20 inline LL dfs(int st,int mul_id,bool limit)
    21 {
    22     if(mul[mul_id]>_9[st])return 0;
    23     if(st==0)return 1;
    24     RG int i,lim=(limit?bin[st]:10);
    25     LL ret=0;
    26     for(i=1;i<lim;++i)
    27         if(mul[mul_id]%i==0)
    28             ret+=f[st-1][id(mul[mul_id]/i)];
    29     if(lim&&bin[st])
    30         if(mul[mul_id]%bin[st]==0)
    31             ret+=dfs(st-1,id(mul[mul_id]/bin[st]),1);
    32     return ret;
    33 }
    34 inline LL query(int id,LL n)
    35 {
    36     LL ret=0;len=0;
    37     while(n)bin[++len]=n%10,n/=10;
    38     for(RG int i=1;i<len;++i)ret+=f[i][id];
    39     return ret+dfs(len,id,1);
    40 }
    41 inline LL calc(LL n)
    42 {
    43     if(!n)return 0;LL ret=0;
    44     for(RG int i=1;mul[i]<=n&&i<=cnt;++i)
    45         ret+=query(i,n/mul[i]);
    46     return ret;
    47 }
    48 int main()
    49 {
    50     RG int i,j,k;
    51     scanf("%lld%lld",&l,&r);
    52     mul[++cnt]=1;
    53     dfs1(0,2,1),sort(mul+1,mul+cnt+1),
    54     cnt=unique(mul+1,mul+cnt+1)-mul-1;
    55     for(_9[0]=i=1;i<=18;++i)_9[i]=_9[i-1]*9;
    56     for(f[0][1]=1,i=1;i<=9;++i)f[1][i]=1;
    57     for(i=2;i<=18;++i)
    58         for(j=1;j<=cnt;++j)if(f[i-1][j])
    59             for(k=1;k<=9;++k)f[i][id(mul[j]*k)]+=f[i-1][j];
    60     printf("%lld
    ", calc(r) - calc(l-1) );
    61 }
    BZOJ1183+BZOJ2713

    bzoj3530

      不知道怎么混进来的AC自动机题目

      前导0的处理需要注意,一开始没有想好

     1 #include <cstdio>
     2 #include <cstring>
     3 using namespace std;
     4 #define L 1510
     5 #define RG register
     6 #define mod 1000000007
     7 char s[L],str[L];
     8 bool ban[L];
     9 int n,cnt,ch[L][11],fail[L],q[L],hd,tl,plan[L][L];
    10 inline int dfs(int rt,int left)
    11 {
    12     if(ban[rt])return plan[rt][left]=0;
    13     if(plan[rt][left])return plan[rt][left];
    14     int ret=0;
    15     for(RG int i=0;i<10;++i)
    16         if(!ban[ch[rt][i]])
    17             ret=(ret+dfs(ch[rt][i],left-1))%mod;
    18     return plan[rt][left]=ret;
    19 }
    20 #define id(c) ((c)-'0')
    21 signed main()
    22 {
    23     RG int i,j,m,rt,l,d,ans=0,good=1;
    24     scanf("%s",s+1),n=strlen(s+1);
    25     scanf("%d",&m);
    26     cnt=1;
    27     for(i=1;i<=m;++i)
    28     {
    29         scanf("%s",str+1),l=strlen(str+1);
    30         for(rt=1,j=1;j<=l;++j)
    31         {
    32             d=str[j]-'0';
    33             if(!ch[rt][d])ch[rt][d]=++cnt;
    34             rt=ch[rt][d];
    35             if(ban[rt])break;
    36         }
    37         ban[rt]=1;
    38     }
    39     for(hd=1,tl=0,i=0;i<10;++i)
    40         if(ch[1][i])q[++tl]=ch[1][i],fail[ch[1][i]]=1;
    41         else ch[1][i]=1;
    42     while(hd<=tl)
    43         for(rt=q[hd++],i=0;i<10;++i)
    44             if(ch[rt][i])d=ch[rt][i],fail[d]=ch[fail[rt]][i],ban[d]|=ban[fail[d]],q[++tl]=d;
    45             else ch[rt][i]=ch[fail[rt]][i];
    46     for(i=1;i<=cnt;++i)if(!ban[i])plan[i][0]=1;
    47     for(i=1;i<=cnt;++i)if(!ban[i])
    48         for(j=1;j<n;++j)if(!plan[i][j])dfs(i,j);
    49     for(i=1;i<n;++i)for(j=1;j<10;++j)
    50         ans=(ans+plan[ch[1][j]][i-1])%mod;
    51     for(rt=1,i=1;i<=n;++i)
    52     {
    53         for(d=s[i]-'0',j=(i==1?1:0);j<d;++j)
    54             if(!ban[ch[rt][j]])ans=(ans+plan[ch[rt][j]][n-i])%mod;
    55         rt=ch[rt][d];
    56         if(ban[rt]){good=0;break;}
    57     }
    58     printf("%d
    ",ans+good);
    59 }
    BZOJ3530

    uoj86

    题解在这里面,综合感不错的题目……

    bzoj3652

    相当于两部分分开求和再除总数然后加权

    第二部分求异或和很好想,统计每位0/1个数然后搞就行

    关于第一部分………在%wq的思路之后打过去了

    第一部分相当于对于每一个数选一个数和它异或和最大

    由于选的那个数也要在n的范围内,所以我们不太好搞

    这样,我们正难则反,先认为每个数的每一位都能贡献上,再减去多余的贡献

    由于n的二进制第一位一定是1,所以在2^(len-1)到n-1这些数一定每一位都能贡献上

    那么我们一开始就拿着0~2^(len-1)-1这些数(len代表n的二进制长度),维护剩下多少数

    从n的高位往低位考虑,如果n的某一位是1,那么这一位如果填0的话,

    现在这一位为1的数(正好占一半)就一定能贡献后面所有位的值(即他们一定不会超限,所以后面可以随意填)

    那么我们把它们扔掉,即更改剩下数的多少

    这个和一开始分析的最高位的情况类似

    反之,如果为0,那么这一位为0的所有数(也是占一半)由于不能填1而无法贡献这一位的异或值

    那么我们在答案中减去对应的值

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 using namespace std;
     5 #define RG register
     6 #define LL long long
     7 #define db double
     8 LL bin[64];
     9 int bit[64],len;
    10 int main()
    11 {
    12     RG int i;LL n,m,tmp,cnt0,cnt1;
    13     db val1=0,val2=0,p,q;
    14     for(bin[0]=i=1;i<=62;++i)bin[i]=bin[i-1]<<1;
    15     scanf("%lld%lf",&n,&p),m=n-1;
    16     tmp=m;while(tmp)bit[++len]=tmp&1,tmp>>=1;
    17     for(i=len;~i;--i)
    18     {    
    19         tmp=n>>(i+1),cnt0=cnt1=tmp*bin[i];
    20         if(n&bin[i])cnt0+=bin[i],cnt1+=(bin[i]-1)&n;
    21         else cnt0+=(bin[i]-1)&n;
    22         val2+=2.0*cnt0*cnt1*bin[i];
    23     }
    24     val2/=n*1.0*n;
    25     val1=n*1.0*(bin[len]-1);tmp=bin[len];
    26     for(i=len;i;--i)
    27         if(bit[i])tmp>>=1;
    28         else val1-=(tmp>>1)*1.0*bin[i-1];
    29     printf("%.10lf
    ",p*val1/n+(1-p)*val2 );
    30 }
    BZOJ3652

    bzoj4513

    感觉是上面一题的加强版

    自己想的是dfs打法,但是由于情况太多无法手动分类讨论,打不出来

    数组定义定义f[i][2][2][2],后面三个0/1分别代表是否满足i<=n,j<=m,i^j>=k

    现在我发现的AC写法(茴香豆的茴有四种写法你知道嘛)

    1.(大部分网上题解使用的)4维数组dp

    发现网上大部分人是用的迭代dp的打法

    和我定义是一样的,可是……

    代码实现出人意料的简洁

    dp写法和dfs写法的确是各有所长

    dp适合用很多for循环和边界特判无脑处理掉大量的分类讨论

    而dfs适合无法很好用for循环枚举的东西

    Ps:dp写法有一个地方不是太懂,就是为什么最后要把数组的每个元素都计算一遍

    我们需要的答案难道不就是ans[1][1][1]吗

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <cstring>
     4 using namespace std;
     5 #define RG register
     6 #define LL long long
     7 LL n,m,k,bin[64],f_ge[64][2][2][2],f_sum[64][2][2][2];
     8 int main()
     9 {
    10     RG int mod,i,ta,tb,tc,a,b,c,x,y,z,t,len,lena,lenb,lenc,bita,bitb,bitc;
    11     LL ans,tmp;scanf("%d",&t);
    12     while(t--)
    13     {
    14         scanf("%lld%lld%lld%d",&n,&m,&k,&mod),--n,--m;
    15         lena=lenb=lenc=0;
    16         tmp=n;while(tmp)++lena,tmp>>=1;
    17         tmp=m;while(tmp)++lenb,tmp>>=1;
    18         tmp=k;while(tmp)++lenc,tmp>>=1;
    19         len=max(lena,max(lenb,lenc));
    20         for(bin[0]=i=1;i<=len;++i)bin[i]=(bin[i-1]<<1)%mod;
    21         memset(f_ge,0,sizeof(f_ge)),memset(f_sum,0,sizeof(f_sum));
    22         f_ge[len+1][1][1][1]=1;ans=0;
    23         for(i=len;~i;--i)
    24         {
    25             bita=(n>>i)&1,bitb=(m>>i)&1,bitc=(k>>i)&1;
    26             for(a=0;a<2;++a)for(b=0;b<2;++b)for(c=0;c<2;++c)
    27                 if(f_ge[i+1][a][b][c])
    28                     for(x=0;x<2;++x)
    29                     {
    30                         if(a && x>bita)break;
    31                         for(y=0;y<2;++y)
    32                         {
    33                             if(b && y>bitb)break;
    34                             z=x^y;
    35                             if(c && z<bitc)continue;
    36                             ta=(a && bita==x)?1:0,tb=(b && bitb==y)?1:0,tc=(c && bitc==z)?1:0;
    37                             f_ge[i][ta][tb][tc]=(f_ge[i][ta][tb][tc]+f_ge[i+1][a][b][c])%mod;
    38                             f_sum[i][ta][tb][tc]=( f_sum[i][ta][tb][tc]+f_sum[i+1][a][b][c])%mod;
    39                             if(z)f_sum[i][ta][tb][tc]=( f_sum[i][ta][tb][tc]+ bin[i]*f_ge[i+1][a][b][c]%mod )%mod;
    40                         }
    41                     }
    42         }
    43         k%=mod;
    44         for(a=0;a<2;++a)for(b=0;b<2;++b)for(c=0;c<2;++c)
    45             ans=(ans+f_sum[0][a][b][c]-k*f_ge[0][a][b][c]%mod+mod)%mod;
    46         printf("%lld
    ",ans);
    47     }
    48 }
    BZOJ4513

    啊……我要再研究一下dfs写法,看看能不能打出来

    upd:我完蛋了,我打不出来2333

    2.wq式dp打法,强大又快速,wq Orzzzzzzzzzzzzzzzzzzzzzzzz

    很巧妙,刷新了我对数位Dp的认识,让我理解更加深入了

    让wq讲了一个多小时,感觉自己智商掉没了2333

    但是还是不太懂,无法用语言描述……

    等我更强了再来补这个做法……

    bzoj3326

    思路大概是很清真的,总的来说就是预处理前i位数的子串和,以及前缀子串之和,然后按照数位DP那样限制转移

    但是……那个转移的式子……

    啊真是让人痛苦,那个式子我总共大改了5遍才打过,并且有很多一开始没有注意到的细节

    以后做题必须要先想好式子

    每一项是什么为什么都要想清楚

    要不特别耽误时间……有的时候船到桥头……就翻船了……

    感觉思维严谨性得到了提高2333

     1 #include <cstdio>
     2 #include <cstring>
     3 using namespace std;
     4 #define RG register
     5 #define mod 20130427
     6 #define N 100010
     7 #define LL long long
     8 char cB[1<<15],*S=cB,*T=cB;
     9 #define getc (S==T&&(T=(S=cB)+fread(cB,1,1<<15,stdin),S==T)?0:*S++)
    10 inline int read()
    11 {
    12     RG int x=0;RG char c=getc;
    13     while(c<'0'|c>'9')c=getc;
    14     while(c>='0'&c<='9')x=10*x+(c^48),c=getc;
    15     return x;
    16 }
    17 inline int Sum(int a){return ((LL)a*(a+1ll)/2)%mod;}
    18 inline int max(int a,int b){return a>b?a:b;}
    19 inline int min(int a,int b){return a<b?a:b;}
    20 int ge2[N],sum2[N],ge3[N],sum3[N],no_zero_sum3[N],B,lena,bit[N],lenb,bin[N];
    21 inline int calc(bool start,int left,int lim,int cnt,int sum,int sum_of_substring )
    22 {
    23     if(lim==0)return 0;
    24     if(start)
    25         return
    26             ( 
    27             (LL) Sum(lim-1) * ge2[left] %mod * bin[left] %mod + //前与后连接之后前面的贡献
    28             (LL) ( lim - 1 ) %mod * sum3[left] %mod + no_zero_sum3[left] %mod +//后面的子串 
    29             (LL) ( lim - 1 ) %mod * sum2[left] %mod//前与后连接之后后面的贡献
    30             )%mod;
    31     int new_sum=( (LL) sum * B %mod * lim %mod + (LL) Sum(lim-1) * cnt %mod ) %mod;
    32     return
    33         ( 
    34         (LL) sum_of_substring * lim %mod * bin[left] %mod + //之前的子串
    35         (LL) new_sum * ge2[left] %mod * bin[left] %mod + //前与后连接之后前面的贡献
    36         (LL) lim %mod * sum3[left] %mod +//后面的子串 不乘cnt
    37         (LL) cnt * lim %mod * sum2[left] %mod//前与后连接之后后面的贡献 ,要乘cnt 因为再前面不同
    38         )%mod;
    39 }
    40 inline int dfs(bool start,int st,int cnt,int sum,int sum_of_substring)
    41 {
    42     if(st==0)return 0;
    43     int new_sum=( (LL) sum * B %mod + (LL) ( cnt + 1 ) * bit[st] %mod )%mod;
    44     return 
    45         ( new_sum + calc(start, st-1 , bit[st] , cnt + 1 , sum , sum_of_substring ) + 
    46         dfs(0, st - 1 , cnt + 1,  new_sum , (sum_of_substring + new_sum)%mod ) )%mod;
    47 }
    48 signed main()
    49 {
    50     RG int i,j,len,ans;
    51     B=read(),lena=read();
    52     for(i=lena;i;--i)bit[i]=read();
    53     lenb=read();len=max(lena,lenb);
    54     if(lena>1||bit[1]>0)
    55     {
    56         --bit[1],j=1;
    57         while(bit[j]<0)bit[j]+=B,--bit[j+1],++j;
    58         while(lena>1&&!bit[lena])--lena;
    59     }
    60     for(bin[0]=ge2[0]=i=1;i<=len;++i)
    61     {
    62         bin[i]=(LL)bin[i-1]*B%mod;
    63         ge2[i]=( ge2[i-1] + bin[i] )%mod;
    64         ge3[i]=(LL) Sum(i) * bin[i] %mod;
    65         sum2[i]=( (LL) sum2[i-1] * B %mod +  Sum ( bin[i] - 1 ) )%mod;
    66         sum3[i]=( (LL) Sum(B-1) * bin[i-1] %mod * ge2[i-1] %mod + (LL)B * sum2[i-1] %mod + (LL) B * sum3[i-1] %mod )%mod;
    67         no_zero_sum3[i]=( (LL) Sum(B-1) * bin[i-1] %mod * ge2[i-1] %mod + 
    68                         (LL) (B - 1) * sum2[i-1] %mod + (LL) (B - 1) * sum3[i-1] %mod + no_zero_sum3[i-1] )%mod;
    69     }
    70     ans=mod-dfs(1,lena,0,0,0);
    71     for(i=lenb;i;--i)bit[i]=read();
    72     printf("%d
    ",(ans+dfs(1,lenb,0,0,0))%mod);
    73 }
    bzoj3326

    其实还有另外一种思路,那就是反过来从前往后走,并且用矩阵乘优化

    这个是wq的原创思路……

    bzoj3598

      没做呢,听说挺简单,但是我没想出来

      这次时间不够了……不想怂题解

      有时间再做……

    这次做的题就是这么多……接下来要去找“有思维难度的DP题”了……加油咯……

  • 相关阅读:
    查看Mysql版本
    Day03_SpringCloud2
    Day01_SpringBoot
    【Java面试题】如何判断一个字符串中某个字符出现的次数?
    你以为这样写Java代码很6,但我看不懂
    smart-socket实战:玩转心跳消息
    JVM 对象分配过程
    Spring Cloud基于Redis实现的分布式锁
    Python10行以内代码能有什么高端操作
    会话技术之Cookie详解
  • 原文地址:https://www.cnblogs.com/LadyLex/p/8490222.html
Copyright © 2011-2022 走看看