BZOJ:2958 序列染色 DP

来源:互联网 发布:5s4g网络怎么设置 编辑:程序博客网 时间:2024/05/14 17:05

bzoj2958 序列染色

题目传送门

Description

  给出一个长度为N由B、W、X三种字符组成的字符串S,你需要把每一个X染成B或W中的一个。
  对于给出的K,问有多少种染色方式使得存在整数a,b,c,d使得:
  1<=a<=b<c<=d<=N
  Sa,Sa+1,…,Sb均为B
  Sc,Sc+1,…,Sd均为W
  其中b=a+K-1,d=c+K-1
  由于方法可能很多,因此只需要输出最后的答案对109+7取模的结果。

Input
  第一行两个正整数N,K
  第二行一个长度为N的字符串S

Output
  一行一个整数表示答案%(109+7)。

Sample Input
5 2
XXXXX
Sample Output
4
数据约定
  对于20%的数据,N<=20
  对于50%的数据,N<=2000
  对于100%的数据,1<=N<=10^6,1<=K<=10^6

Solution

  很容易想到N^2的做法(简单的DP)。
  f[i][j][h][s]——i表示到了第i个字符,状态为j(0表示没有k个B,1表示有k个B没有k个W,2表示既有k个B又有k个W),最后一位为h(0表示B,1表示W),最后一位有连续s个。
  具体转移就不说了。
  其实s是不用记的(F[i][j][h]),那怎么转移状态j呢?
  现有状态需要保证连续的B后有一个W,连续的W后有一个B,答案就是F[n+1][2][0],在第n+1为设为B,最后一位选B不会对答案有影响。
  假如第i位是B,F[i][j][0]=F[i-1][j][1]+F[i-1][j][0];(其他同理,先不考虑j)
  若第i-k+1位到第i位没有W(可以把所有的X变为B,使得有k个B),F[i][1][0]=F[i][1][0]+F[i-k][0][1];
  但依照第一条原则,F[i][0][0]是胡乱转移的,而从F[i-k][0][1]转移会有已经满足中间有k个B的情况,减掉重复的即可。F[i][0][0]=F[i][0][0]-F[i-k][0][1];

PS:DP神题,容斥大法好 残忍暴力水50。

CODE

#include<cstdio>#include<algorithm>#define imax(a,b) ((a>b)?(a):(b))typedef long long ll;using namespace std;typedef long long ll;const ll mods=1e9+7;const int N=1000010;int n,m,B[N],W[N];ll F[N][3][2];char st[N];int main(){    freopen("2237.in","r",stdin);    freopen("2237.out","w",stdout);    scanf("%d%d%s",&n,&m,st+1);    st[++n]='X';    for(int i=1;i<=n;i++)    {        B[i]=B[i-1]+(st[i]=='B');        W[i]=W[i-1]+(st[i]=='W');    }    F[0][0][1]=1ll;    for(int i=1;i<=n;i++)    {        if(st[i]!='W')         for(int j=0;j<3;j++) F[i][j][0]=(F[i-1][j][1]+F[i-1][j][0])%mods;        if(st[i]!='B')        for(int j=0;j<3;j++) F[i][j][1]=(F[i-1][j][1]+F[i-1][j][0])%mods;        if(i<m) continue;        if(st[i]!='W' && W[i]==W[i-m])        {            F[i][1][0]=(F[i][1][0]+F[i-m][0][1])%mods;            F[i][0][0]=(F[i][0][0]-F[i-m][0][1])%mods;        }        if(st[i]!='B' && B[i]==B[i-m])        {            F[i][2][1]=(F[i][2][1]+F[i-m][1][0])%mods;            F[i][1][1]=(F[i][1][1]-F[i-m][1][0])%mods;        }    }    printf("%lld\n",(F[n][2][0]+mods)%mods);    return 0;}
原创粉丝点击