在很久很久很久以后,我终于又回到了coder的舞台。
那么我们来水一发dp吧!
好懒啊不想动

字符染色

【原题】BZOJ 2958

题目描述
给出一个长度为N由B、W、X三种字符组成的字符串S,你需要把每一个X染成B或W中的一个。

输入格式 2237.in
第一行两个整数N和K。
第二行一个长度为N的字符串。

输出格式 2237.out
一个整数表示答案。

输入样例 2237.in
5 2
XXXXX
输出样例 2237.out
4
数据规模:
对于20%的数据, N <= 20
对于50%的数据, N <= 2000
对于100%的数据, 1 <= N, K <= 1000000

【思路】
一看这题,显然后面的方案数是可以从前面以某种玄学的方式推过来的,那么考虑dp。

由于条件的限制性,我们若是一位一位作dp,是无法处理有连续一段长度为k这个东西的。这样一来,我们就要考虑多开一维记录是否有连续一段B/W长度为k,不难发现,需要记录的实际上只有3种情况——BW都不满足,B满足,BW都满足。

好的,接下来分析如何判断是否能满足连续一段都为B/W。
其实挺容易想到的,就是利用前缀和记录前面一共有几个B/W(用hw和hb记录吧),例如我们要判断B,那么我们只需要判断hw[i]与hw[i-k]是不是相等即可。

接下来就是转移了啊~~~
用f[i][j][k]表示到了第i位,状态是j(即0是没有连续段长为k的,1是B有W没 有,2是BW都有),k是这一位选了什么(0是B,1是W)
保证连续的B后面一定有一个W,连续的W后有一个B,答案就是f[n+1][2][0]

假设这一位选B有

f[i][j][0]=f[i-1][j][1]+f[i-1][j][0]
if(i-k+1到i没有W)f[i][1][0]=f[i][1][0]+f[i-k][0][1];

然而这样会有重复,由于f[i][0][0]是乱转移,中间有可能已经有B了,所以:

if(i-k+1到i没有W)f[i][0][0]=f[i][0][0]-f[i-k][0][1];

这样就可以了??是吧。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;const int mod=1e9+7;
const int MAXN=1e6+10;
int f[MAXN][3][3];//the ith,the state,this one choice//state 0=none,1=have k B,2=have k W
int hb[MAXN],hw[MAXN];
int n,k;
char st[MAXN];/*void debug()
{for(int i=1;i<=n;++i){for(int j=0;j<=2;++j){printf("%d ",f[i][j][0]);}printf("\n");}printf("\n");for(int i=1;i<=n;++i){for(int j=0;j<=2;++j){printf("%d ",f[i][j][1]);}printf("\n");}printf("\n");
}*/void init()
{scanf("%d%d",&n,&k);scanf("%s",st+1);st[++n]='X';for(int i=1;i<=n;++i){hb[i]=hb[i-1];hw[i]=hw[i-1];if(st[i]=='B')hb[i]++;if(st[i]=='W')hw[i]++;}
}void solve()
{f[0][0][1]=1;for(int i=1;i<=n;++i){if(st[i]=='B')for(int j=0;j<3;++j)f[i][j][0]=(f[i-1][j][0]+f[i-1][j][1])%mod;elseif(st[i]=='W')for(int j=0;j<3;++j)f[i][j][1]=(f[i-1][j][0]+f[i-1][j][1])%mod;elsefor(int j=0;j<3;++j){f[i][j][0]=(f[i-1][j][0]+f[i-1][j][1])%mod;f[i][j][1]=(f[i-1][j][0]+f[i-1][j][1])%mod;}if(i<k)continue;if(st[i]=='B' || st[i]=='X'){if(hw[i]==hw[i-k]){f[i][1][0]=f[i][1][0]+f[i-k][0][1];f[i][1][0]%=mod;f[i][0][0]=f[i][0][0]-f[i-k][0][1]+mod;f[i][0][0]%=mod;}}if(st[i]=='W' || st[i]=='X'){if(hb[i]==hb[i-k]){f[i][2][1]=f[i][2][1]+f[i-k][1][0];f[i][2][1]%=mod;f[i][1][1]=f[i][1][1]-f[i-k][1][0]+mod;f[i][1][1]%=mod;}}}
//  debug();printf("%d\n",f[n][2][0]);
}int main()
{freopen("2237.in","r",stdin);freopen("2237.out","w",stdout);init();solve();return 0;
}

============我是分割线============

ABA字符串

【原题】BZOJ 3620

题目描述
给出一个长度为n的字符串(均为小写字母),以及一个整数k。
问该字符串的所有子串中,能被切分为A+B+A的形式且 len(A) >= k, len(B) >= 1 的子串数量有多少。

输入格式 2240.in
第一行一个字符串
第二行一个整数k

输出格式 2240.out
一个整数表示答案。

输入样例 2240.in
abcabcabc
2
输出样例 2240.out
8
数据规模:
对于30%的数据: 1 <= n <= 100
对于100%的数据: 1 <= n <= 10000, 1 <= k <= 100

n<=10000 显然是直接给你暴力水的- -

看到字符串匹配,立马就有什么AC自动机之类的东西出来。
于是我们思路清晰,用KMP来暴力

枚举子串的左端点,然后枚举右端点
对于每个子串S我们要判定是否存在一个长度在[k,(|S|-1)>>1]之间的前缀与后缀匹配
那我们就求出长度不超过(|S|-1)>>1的最长前后缀,判断是否>=k即可

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;const int MAXN=10010;
int nex[MAXN];
char s[MAXN];
int k,n,ans;int main()
{freopen("2240.in","r",stdin);freopen("2240.out","w",stdout);scanf("%s",&s);scanf("%d",&k);n=strlen(s);ans=0;for (int i=1;i<=n-k;i++){nex[0]=nex[1]=0;int x=0;
//      printf("0 0 ");for (int j=2; j<=n-i+1; j++){while(x && s[i-1+x]!=s[i+j-2]) x=nex[x];if (s[i+x-1]==s[i+j-2]) x++;nex[j]=x;
//          printf("%d ",nex[j]);}
//      printf("\n");int tmp=ans;x=0;for (int j=2;j<=n-i+1;j++){while(x && s[i-1+x]!=s[i+j-2]) x=nex[x];if (s[i-1+x]==s[i+j-2]) x++;while((x<<1|1)>j) x=nex[x];if (x>=k) ans++;}
/*      printf("!!!%d\n",ans-tmp);for(int j=0;j<=n;++j)printf("%d ",nex[j]);printf("\n");*/}printf("%d\n",ans);return 0;
}

==========凑热闹的分割线===========

The Intriguing Obsession

【原题】codeforces 869C

【题目大意】
有三个集合,分别含有a、b、c个点,要求给这些点连线,也可以全都不连,要求连接后,每两点距离为1,在同一集合的两点最短距离至少为3,问多少种不同的连接方案。

【思路】
首先我们简化问题,思考集合两两之间的关系。我们发现,若每两个集合都保证满足条件,那最后结果一定满足条件。

那么问题就变得比较简单了,两个集合间若要最短距离至少为3,那每个集合中的点只能同时与另一个集合中的一个点相连。

那么不难得出,若两个集合间需要连k条线,则可以在集合A中选k个点,在集合B中选k个点,共有k!种连接方式,即

C[A][k]*C[B][k]*k!。

两个集合间最少可连0条,最多可连min(A,B),因此k的范围为0~min(A,B)。
这是组合数的思考方式。

然后我们还可以引申一下,用个dp来搞搞这个东西
我们发现每个点其实就是选和不选的区别,所以

dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*j;

就这样。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;typedef long long LL;
const int mod=998244353;
const int MAXN=5005;
int a,b,c;
LL ans,dp[MAXN][MAXN];void init()
{dp[0][0]=1;for(int i=0;i<=5000;++i)dp[0][i]=dp[i][0]=1;for(int i=1;i<=5000;++i)for(int j=1;j<=5000;++j)dp[i][j]=(dp[i-1][j]+dp[i-1][j-1]*1ll*j)%mod;
}void solve()
{scanf("%d%d%d",&a,&b,&c);ans=(dp[a][b]*dp[b][c]%mod)*dp[c][a]%mod;printf("%I64d\n",ans);
}int main()
{
//  freopen("C.in","r",stdin);
//  freopen("C.out","w",stdout);init();solve();return 0;
}

说实话也并不是很想打其他了啊www
那就到这里结束吧~~

撒花~~

【dp专题】在经历了时空扭曲后的总结相关推荐

  1. DP专题考试总结(4)

    最近努力学(tui)习(fei)了DP专题,然后考试又挂了,然后就没有然后了. 对此,我只想说-- 吾每念,常痛于骨髓,顾计不知所出耳! 广场铺砖问题 期望得分:40 实际得分:10 Descript ...

  2. DP专题考试总结(2)

    最近努力学(tui)习(fei)了DP专题,然后就被烤焦了,然后就没有然后了. 对此,我只想说-- DP made me Boom-Sha-Ka-La-Ka 加分二叉树 期望得分:0 实际得分:0 D ...

  3. codeforces的dp专题

    1.(467C)http://codeforces.com/problemset/problem/467/C 题意:有一个长为n的序列,选取k个长度为m的子序列(子序列中不能有位置重复),求所取的k个 ...

  4. codeforces(牛客网dp专题,排序)

    链接:https://ac.nowcoder.com/acm/problem/21314 来源:牛客网 牛牛正在打一场CF 比赛时间为T分钟,有N道题,可以在比赛时间内的任意时间提交代码 第i道题的分 ...

  5. 牛客网dp专题 数位dp

    文章目录 数位dp 例题: NC116652 uva11038 How many 0's NC15035 送分了QAQ NC20669 诡异数字 NC20665 7的意志 NC17385 Beauti ...

  6. 多重背包(dp专题)

    题目大意:输入n,代表有n种数,接下来n个数代表n种数,再接下来n个数代表每种数有多少个,在输入K,代表用这些数要加成的和 问你是否能加为K,能输出yes,不能输出no 这是一个典型的多重背包问题,可 ...

  7. 简单的dp(dp专题)

    题目链接:https://vjudge.net/contest/216347#problem/C Alice gets two sequences A and B. A easy problem co ...

  8. 01背包 (dp专题)

    01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2至Wn,与之相对应的价值为P1,P2至Pn.01背包是背包问题中最简单的问题.01背包的约束条件是给定几种物品,每种物品有 ...

  9. Day41——Dp专题

    文章目录 四.完全背包 01背包的核心代码 完全背包的核心代码 12.零钱兑换 II 13.组合总和 Ⅳ 14. 爬楼梯(进阶版) 15.零钱兑换 16.完全平方数 17.单词拆分 四.完全背包 完全 ...

最新文章

  1. jq查找字段忽略html标签,jquery内容过滤选择器有哪些?
  2. hdu 1575Tr A
  3. springboot 增加prometeus监控
  4. jvm gc阻塞时长 占比_jvm进行转义分析需要多长时间? 可能比您想象的要长。
  5. c语言查看进程模块,计算机二级考试C语言辅导:进程模块查看
  6. 智能手机之新手篇[转]
  7. python list排序方法_python中List的sort方法指南
  8. SQL server 2016数据库 下载安装
  9. hbase 源代码解析(2)HAdmin 的表创建过程
  10. WIFi6与WIFI5技术路线演进及优势
  11. 解锁JMP 15 DOE新功能--组正交超饱和设计(GO SSD)
  12. xdb 服务_如何禁用Oracle的XDB及修改XDB服务端口
  13. java水果忍者7723_水果忍者之天下第一
  14. 蓝牙bluetooth
  15. 计算机怎么通过网线共享网络,怎样用一根网线联接两台电脑实现网络共享?
  16. Java下载文件时文件名中的中文变成下划线,其他正常
  17. 宏基Acer4710系列宝石本白屏闪屏等屏幕疑难杂症
  18. CSS课堂案例8-小米布局
  19. 啦百茁仲尾芬八敌直就乖虏举删捅
  20. Spring Bean作用域与生命周期

热门文章

  1. php批量请求url_php中请求url的五种方法总结
  2. Python带你采集4K高清壁纸,超惊艳
  3. pgsql 无法删除表 CASCADE无效
  4. FastReport Online Designer 2023
  5. vba自动适应行和列
  6. html文字翻牌效果,css3翻牌效果
  7. 中兴与日企联盟 目标锁定当地WCDMA市场
  8. vue实现tabs侧边导航栏点击内容跳转到对应位置,且内容滚动导航栏切换,封装直接用
  9. [Hades_方法]Hades学习方法和资料
  10. 使用java实现注册登录信息验证