1. 程式人生 > >2019.01.03-dtoj-4104-yjqaa

2019.01.03-dtoj-4104-yjqaa

ace val 一個 char 描述 inf names sin pac

題目描述:


技術分享圖片

算法標簽:數位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

2019.01.03-dtoj-4104-yjqaa