• 【BZOJ2958】序列染色(动态规划)


    点此看题面

    大致题意: 给定一个由"X","B","W"三种字符组成的字符串,让你把所有"X"替换为"B"或"W",使得存在一段长度为(m)、全是"B"的子串,且其后还存在一段长度为(m)、全是"W"的子串。求方案数。

    动态规划

    发现现在做题总是把题目想复杂,其实这道题还是比较简单的。。。

    我们设(f_{i,0/1},g_{i,0/1},h_{i,0/1})分别表示在前(i)个字符中不存在"B"的子串存在"B"的子串但其后不存在"W"的子串满足了题目的要求,且最后一个选择的字符是"B"/"W"的方案数。

    首先,如果这一位上不是"B"(即是"X"或"W"),那么我们可以直接从上一位转移得到(f_{i,0},g_{i,0},h_{i,0}),同理在这一位上不是"W"时可以直接转移得到(f_{i,1},g_{i,1},h_{i,1})

    但仅仅这样转移肯定是不够的,我们还需要考虑从一种状态到另一种状态的过渡转移。

    即,如果之前的(m)位不存在"W"(即可以全部染成"B"),我们就令(f_{i,1})减去(f_{i-m,0})(g_{i,1})加上(f_{i-m,0})

    注意要从第二维为(0)的情况转移,是为了避免一段长度大于(m)的子串被计算多次。

    同理,如果之前的(m)为不存在"B",我们就令(g_{i,0})减去(g_{i-m,1})(h_{i,0})加上(g_{i-m,1})

    于是这道题就做完了,最终答案就是(h_{n,0}+h_{n,1})

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 1000000
    #define X 1000000007
    #define Inc(x,y) ((x+=(y))>=X&&(x-=X))
    #define Dec(x,y) ((x-=(y))<0&&(x+=X))
    using namespace std;
    int n,m,f[N+5][2],g[N+5][2],h[N+5][2],s[N+5][2];char st[N+5];
    int main()
    {
    	RI i;for(scanf("%d%d%s",&n,&m,st+1),i=1;i<=n;++i)
    		s[i][0]=s[i-1][0],s[i][1]=s[i-1][1],st[i]^'X'&&++s[i][st[i]=='B'];//预处理前缀和以判断一段区间内是否存在某个数
    	for(f[0][0]=i=1;i<=n;++i)//初始化时默认第0位填0
    		st[i]^'B'&&(f[i][0]=(f[i-1][0]+f[i-1][1])%X,g[i][0]=(g[i-1][0]+g[i-1][1])%X,h[i][0]=(h[i-1][0]+h[i-1][1])%X),//可填0
    		st[i]^'W'&&(f[i][1]=(f[i-1][0]+f[i-1][1])%X,g[i][1]=(g[i-1][0]+g[i-1][1])%X,h[i][1]=(h[i-1][0]+h[i-1][1])%X),//可填1
    		i>=m&&s[i-m][0]==s[i][0]&&(Dec(f[i][1],f[i-m][0]),Inc(g[i][1],f[i-m][0])),//可以得到一段B串
    		i>=m&&s[i-m][1]==s[i][1]&&(Dec(g[i][0],g[i-m][1]),Inc(h[i][0],g[i-m][1]));//可以得到一段W串
    	return printf("%d
    ",(h[n][0]+h[n][1])%X),0;//输出答案
    }
    
  • 相关阅读:
    Javaweb开发环境与搭建
    剑指Offer:面试题32——从1到n整数中1出现的次数(java实现)
    剑指Offer:面试题31——连续子数组的最大和(java实现)
    剑指Offer:面试题30——最小的k个数(java实现)
    剑指Offer:面试题29——数组中出现次数超过一半的数字(java实现)
    剑指Offer:解决难题时的三大方法
    剑指Offer:面试题28——字符串的排列(java实现)(待序)
    剑指Offer:面试题27——二叉搜索树与双向链表(java实现)
    剑指Offer:面试题26——复制复杂的链表(java实现)
    剑指Offer:面试题25——二叉树中和为某一值的路径(java实现)
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ2958.html
Copyright © 2020-2023  润新知