BZOJ2958 序列染色(动态规划)
令f[i][0/1/2][0/1]表示前i位,不存在满足要求的B串和W串/存在满足要求的B串不存在W串/存在满足要求的B串和W串,第i位填的是B/W的方案数。转移时考虑连续的一段填什么。大讨论一波后瞎优化一波就成线性的了。k=1应该是要特判一下的不过数据里没有那就不管了。
成功的把这么短的题面都看错了一次。弱智dp写的心态爆炸。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 1000010 #define P 1000000007 int n,m,a[N],pre[N][2],p[2],f[N][3][2],delta[3][2]; void inc(int &x,int y){x+=y;if (x>=P) x-=P;} int main() { #ifndef ONLINE_JUDGE freopen("bzoj2958.in","r",stdin); freopen("bzoj2958.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(); char c=getchar();while (c<'A'||c>'Z') c=getchar(); for (int i=1;i<=n;i++) { a[i]=(c=='X')?2:(c=='B'?0:1); if (a[i]<2) p[a[i]]=i; pre[i][0]=p[0];pre[i][1]=p[1]; c=getchar(); } a[0]=2; f[0][0][0]=f[0][0][1]=1; delta[0][0]=(a[1]!=1),delta[0][1]=(a[1]!=0); for (int i=1;i<=n;i++) { f[i][0][0]=delta[0][0],f[i][1][0]=delta[1][0],f[i][2][0]=delta[2][0]; f[i][0][1]=delta[0][1],f[i][1][1]=delta[1][1],f[i][2][1]=delta[2][1]; inc(delta[0][0],f[i][0][1]);inc(delta[1][0],f[i][1][1]);inc(delta[2][0],f[i][2][1]); inc(delta[0][1],f[i][0][0]);inc(delta[1][1],f[i][1][0]);inc(delta[2][1],f[i][2][0]); if (pre[i+1][1]<i-m+2) { inc(delta[0][0],(P-f[i-m+1][0][1])%P); inc(delta[1][0],f[i-m+1][0][1]); } if (pre[i+1][0]<i-m+2) { inc(delta[1][1],(P-f[i-m+1][1][0])%P); inc(delta[2][1],f[i-m+1][1][0]); } if (a[i+1]==0) delta[0][1]=delta[1][1]=delta[2][1]=0; if (a[i+1]==1) delta[0][0]=delta[1][0]=delta[2][0]=0; } cout<<(f[n][2][0]+f[n][2][1])%P; return 0; }