2019.01.03-dtoj-4104-yjqaa

题目描述:


算法标签:数位DP

 思路:

以下叫x=x-1为操作一,x=x-2i为操作2.
对于一个数,我们可以把它分成两部分,第一部分只需要用操作2,第二部分需用用若干个操作2,是序列变成100...0000再使用操作1,再把该为0的部分使用操作2。

分成两部分分别从头和尾dp,最后在合起来。

以下代码:

#include<bits/stdc++.h>
#define il inline
using namespace std;
const int N=502,p=1e9+7;char s[N];
int n,f[N][2],g[N][2][2],fw[N][2],gw[N][2][2],a[N],ans;
il int mu(int x,int y){if(x+y>=p)return x+y-p;return x+y;}
int main()
{
    scanf(" %s",s+1);n=strlen(s+1);for(int i=1;i<=n;i++)a[i]=s[i]-'0';
    gw[n+1][0][0]=1;
    for(int i=n;i>1;i--)for(int j=0;j<2;j++)for(int z=0;z<2;z++){
        if(!gw[i+1][j][z])continue;
        for(int ax=0;ax<2;ax++)for(int bx=0;bx<2;bx++){
            int jj,zz=(z|(ax==1&&bx==0)),val=(ax==0)+(bx==1);
            if(a[i]==bx)jj=j;else if(a[i]<bx)jj=1;else jj=0;
            if(ax==0&&bx==1)zz=0;
            gw[i][jj][zz]=mu(gw[i][jj][zz],gw[i+1][j][z]);
            g[i][jj][zz]=mu(g[i][jj][zz],mu(g[i+1][j][z],1ll*val*gw[i+1][j][z]%p));
        }
    }
    fw[0][1]=1;
    for(int i=1;i<=n;i++)for(int j=0;j<2;j++){
        if(!fw[i-1][j])continue;
        for(int ax=0;ax<2;ax++)for(int bx=0;bx<2;bx++){
            if(ax==1&&bx==0)continue;if(j==1&&a[i]<bx)continue;
            int jj=(j==1&&a[i]==bx),val=bx-ax;
            fw[i][jj]=mu(fw[i][jj],fw[i-1][j]);
            f[i][jj]=mu(f[i][jj],mu(f[i-1][j],1ll*val*fw[i-1][j]%p));
            if(val&&i!=n){
                ans=mu(ans,mu(1ll*fw[i-1][j]*g[i+1][0][1]%p,mu(1ll*gw[i+1][0][1]*fw[i-1][j]%p,1ll*f[i-1][j]*gw[i+1][0][1]%p)));
                if(!jj)ans=mu(ans,mu(1ll*fw[i-1][j]*g[i+1][1][1]%p,mu(1ll*gw[i+1][1][1]*f[i-1][j]%p,1ll*fw[i-1][j]*gw[i+1][1][1]%p)));
            }
        }
    }
    ans=mu(ans,mu(f[n][0],f[n][1]));
    printf("%d\n",ans);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Jessie-/p/10217687.html