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<=106,1<=K<=106

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;
}

BZOJ:2958 序列染色 DP的更多相关文章

  1. bzoj2958: 序列染色(DP)

    2958: 序列染色 题目:传送门 题解: 大难题啊(还是我太菜了) %一发大佬QTT 代码: #include<cstdio> #include<cstring> #incl ...

  2. [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT)

    [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT) 题面 小C有一个集合S,里面的元素都是小于质数M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数 ...

  3. [BZOJ 3791] 作业 【DP】

    题目链接:BZOJ - 3791 题目分析 一个性质:将一个序列染色 k 次,每次染连续的一段,最多将序列染成 2k-1 段不同的颜色. 那么就可以 DP 了,f[i][j][0|1] 表示到第 i ...

  4. BZOJ 1251 序列终结者(Splay)

    题目大意 网上有许多题,就是给定一个序列,要你支持几种操作:A.B.C.D.一看另一道题,又是一个序列要支持几种操作:D.C.B.A.尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技术 ...

  5. [bzoj]2962序列操作

    [bzoj]2962序列操作 标签: 线段树 题目链接 题意 给你一串序列,要你维护三个操作: 1.区间加法 2.区间取相反数 3.区间内任意选k个数相乘的积 题解 第三个操作看起来一脸懵逼啊. 其实 ...

  6. BZOJ 5306 [HAOI2018] 染色

    BZOJ 5306 [HAOI2018] 染色 首先,求出$N$个位置,出现次数恰好为$S$的颜色至少有$K$种. 方案数显然为$a_i=\frac{n!\times (m-i)^{m-i\times ...

  7. bzoj 1858 序列操作

    bzoj 1858 序列操作 带有随机多个区间单值覆盖的区间操作题,可考虑用珂朵莉树解决. #include<bits/stdc++.h> using namespace std; #de ...

  8. codevs 1962 马棚问题--序列型DP

    1962 马棚问题  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题目描述 Description 每天,小明和他的马外出,然后他们一边跑一边玩耍.当他们结束 ...

  9. Educational Codeforces Round 62 (Rated for Div. 2)E(染色DP,构造,思维,组合数学)

    #include<bits/stdc++.h>using namespace std;const long long mod=998244353;long long f[200007][2 ...

随机推荐

  1. Monad Maybe

    在上一篇, 我们创建了第一个Monad,Indentity<T>, 它可能是最简单的Monad, 使我们可以快速了解Monad的模式,而不用陷入细节.接下来我们创建一个有用的Monad, ...

  2. 5) 十分钟学会android--ActionBar知识串烧

    建立ActionBar Action bar 最基本的形式,就是为 Activity 显示标题,并且在标题左边显示一个 app icon.即使在这样简单的形式下,action bar对于所有的 act ...

  3. 【Oracle】RMAN备份

    1. 完全备份 RMAN> backup as backupset database; Starting allocated channel: ORA_DISK_1 channel ORA_DI ...

  4. Session和Cookie对比详解

    会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话.常用的会话跟踪技术是Cookie与Session.Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端 ...

  5. 分层利器 facade

    Facade(外观)模式为子系统中的各类(或结构与方法)提供一个简明一致的界面,隐藏子系统的复杂性,使子系统更加容易使用.

  6. 怎么看时序图--nand flash的读操作详解 (转)

    这篇文章不是介绍 nand flash的物理结构和关于nand flash的一些基本知识的.你需要至少了解 你手上的 nand flash的物理结构和一些诸如读写命令 操作的大概印象,你至少也需要看过 ...

  7. day27-3 matplatlib模块

    目录 matplotlib 条形图 折线图 散点图 matplotlib 图形可视化,主要用来画图 别问,问就是看不懂 条形图 import matplotlib.pyplot as plt # 只识 ...

  8. C语言基础 (5) 常用操作符

    01 课程回顾 变量的起名:字母数字下划线 不能是关键字 常量 变量提升:老的编译器这样会报错 运算符:sizeof.+.-.x … … 进制: 1111 8421 计算机几乎都是二进制系统,而且是以 ...

  9. nodejs 使用crypto实现sha256\md5加密

    var crypto = require('crypto'); var hash = crypto.createHash('sha256');// sha256或者md5 hash.update('1 ...

  10. groupadd(创建组)重要参数介绍

    -g :值定用户组GID值.除非接 -o 参数(如:groupadd -g 666 -o oldboy),否则ID值必须是唯一的数字(不能为负数). 如果不指定 -g 参数,则默认从500开始