BZOJ 2958: 序列染色 && BZOJ 3193: [JLOI2013]地形生成 —— 肆虐的DP
来源:互联网 发布:淘宝pv和uv是什么意思 编辑:程序博客网 时间:2024/04/29 05:13
前言
从前,我有两篇题解的坑还没有填,一道是DP,另一道也是DP。
BZOJ 2958: 序列染色
Description
给出一个长度为N由B、W、X三种字符组成的字符串S,你需要把每一个X染成B或W中的一个。
对于给出的K,问有多少种染色方式使得存在整数a,b,c,d使得:
1<=a<=b
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
一行一个整数表示答案%(10^9+7)。
Sample Input
5 2
XXXXX
Sample Output
4
数据约定
对于20%的数据,N<=20
对于50%的数据,N<=2000
对于100%的数据,1<=N<=10^6,1<=K<=10^6
解题思路(DP+补偿转移)
暴力就不说了,超时or难算,优雅的正解就在下面。
我们考虑记
很明显,如果当前这位不是W的话
不是B也一样。
这里是没有那么多的XJB转移,在这里不符合状态的那部分的方案也暂且记住,比如j=0的状态在乱转K位后包含了1,1包含了2等等。
然后如果当前不是W且连续K个都没有W的话,我们可以转移
然后将前面乱转移多的那部分减去 (连续K个累计的一齐减去)
这里可以称作补偿转移,或者就是容斥原理。
连续一段都是W的转移也一样,将
炒鸡棒的DP,先乱转移一段,“欲擒故纵”,最后在特定的时候一齐减去多余的。
一开始就让第0个位置放W,最后的答案就是
时间复杂度:
做这种题要么算出重复的减掉,要么直接算不重复的。往往前者要用容斥原理,后者要用巧妙的DP。
嫉妒使我补偿转移。
代码
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cstdlib>#include <cmath>#define Mod 1000000007#define N 1000010using namespace std;int n, K, sumB[N], sumW[N], f[N][3][2];char s[N];int main(){ scanf("%d%d", &n, &K); scanf("%s", &s); f[0][0][1] = 1; for(int i = 1; i <= n; i++){ sumB[i] = sumB[i-1] + (s[i-1] == 'B'); sumW[i] = sumW[i-1] + (s[i-1] == 'W'); if(s[i-1] != 'W') for(int j = 0; j < 3; j++) f[i][j][0] = (f[i-1][j][0] + f[i-1][j][1]) % Mod; if(s[i-1] != 'B') for(int j = 0; j < 3; j++) f[i][j][1] = (f[i-1][j][0] + f[i-1][j][1]) % Mod; if(i < K) continue; if(s[i-1] != 'W' && sumW[i] == sumW[i-K]){ f[i][1][0] = (f[i][1][0] + f[i-K][0][1]) % Mod; f[i][0][0] = (f[i][0][0] - f[i-K][0][1] + Mod) % Mod; } if(s[i-1] != 'B' && sumB[i] == sumB[i-K]){ f[i][2][1] = (f[i][2][1] + f[i-K][1][0]) % Mod; f[i][1][1] = (f[i][1][1] - f[i-K][1][0] + Mod) % Mod; } } printf("%d\n", (f[n][2][0] + f[n][2][1]) % Mod); return 0;}
BZOJ 3193: [JLOI2013]地形生成
Description
最近IK正在做关于地形建模的工作。其中一个工作阶段就是把一些山排列成一行。每座山都有各不相同的标号和高度。为了遵从一些设计上的要求,每座山都设置了一个关键数字,要求对于每座山,比它高且排列在它前面的其它山的数目必须少于它的关键数字。
显然满足要求的排列会有很多个。对于每一个可能的排列,IK生成一个对应的标号序列和等高线序列。标号序列就是按顺序写下每座山的标号。等高线序列就是按顺序写下它们的高度。例如有两座山,这两座山的一个合法排列的第一座山的标号和高度为1和3,而第二座山的标号和高度分别为2和4,那么这个排列的标号序列就是1 2,而等高线序列就是3 4.
现在问题就是,给出所有山的信息,IK希望知道一共有多少种不同的符合条件的标号序列和等高线序列。
Input
输入第一行给出山的个数N。接下来N行每行有两个整数,按照标号从1到N的顺序分别给出一座山的高度和关键数。
Output
输出两个用空格分隔开的数,第一个数是不同的标号序列的个数,第二个数是不同的等高线序列的个数。这两个答案都应该对2011取模,即输出两个答案除以2011取余数的结果
Sample Input
2
1 2
2 2
Sample Output
2 2
HINT
对于所有的数据,有1<=N<=1000,所有的数字都是不大于10^9的正整数。
解题思路(DP+组合数学)
这道题我考试时是不会做的,过了好长时间了,又有点忘了。
考虑第一问:将山按高度从大到小排序插入,因为有相等的高度,所以排在第i的数可以插入的位置有
第二问就比较麻烦了,里面有个组合数学的DP,还有个前缀和优化(好像只优化了空间)。
照样把高度相同的一起考虑,高度相同按关键值升序排。然后根据乘法原理乘起来。在就是把x个一样的球放入y个不同位置的方案,就是不管顺序,取组合数。记
然后发现可以滚动,变成
注意这里不插入的方案是有1个的,用这里有点懵B)。
当前高度下的答案是
时间复杂度
DP要消除顺序的限制,一般要排序,强制规定顺序,使其能够正确转移,与排列组合有关的DP的固定套路要掌握,比如枚举取走的与剩下的状态是一一对应的(简单数学都不会就完了)。
代码
#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#include <cmath>#include <iostream>#define N 1010#define M 2011using namespace std;int n, ans1 = 1, ans2 = 1, f[N];struct Data{ int h, num; bool operator < (const Data& Q)const {return h > Q.h || (h == Q.h && num < Q.num);}}mt[N];int main(){ scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d%d", &mt[i].h, &mt[i].num), mt[i].num --; sort(mt+1, mt+n+1); for(int i = 1, t = 1; i <= n; i = ++t){ while(t < n && mt[t].h == mt[t+1].h) ++ t; memset(f, 0, sizeof(f)); f[0] = 1; for(int j = i; j <= t; j++){ ans1 = (ans1 * (min(i, mt[j].num+1) + j - i)) % M; for(int k = 1; k <= min(i-1, mt[j].num); k++) f[k] = (f[k] + f[k-1]) % M; } int temp = 0; for(int j = 0; j <= min(i-1, mt[t].num); j++) temp = (temp + f[j]) % M; ans2 = (ans2 * temp) % M; } printf("%d %d\n", ans1, ans2); return 0;}
总结
一入DP深似海,从此智商是路人。
我已和魔女签订契约,是不能成为神的朋友的。
- BZOJ 2958: 序列染色 && BZOJ 3193: [JLOI2013]地形生成 —— 肆虐的DP
- BZOJ 3193: [JLOI2013]地形生成【计数dp
- [bzoj 3193][JLOI2013]地形生成
- BZOJ 3193 JLOI2013 地形生成 组合数学
- [DP] BZOJ 2958 序列染色
- BZOJ:2958 序列染色 DP
- BZOJ 2958&3269: 序列染色
- 【bzoj3193】[JLOI2013]地形生成 dp+组合数学
- Bzoj3193:[JLOI2013]地形生成:dp+组合数学
- bzoj3193 [JLOI2013]地形生成(dp+组合数学)
- bzoj 2958: 序列染色 递推
- BZOJ 1304 叶子的染色 树形DP
- [树形DP]BZOJ 4033—— [HAOI2015]树上染色
- bzoj3193【JLOI2013】地形生成
- BZOJ 1304: [CQOI2009]叶子的染色 树形DP
- BZOJ 1304: [CQOI2009]叶子的染色 树形dp
- 【BZOJ 3190】 [JLOI2013]赛车
- BZOJ 3190 [JLOI2013]赛车
- 如何垂直居中一个DIV
- Aria2GUI的配置方法
- 【整理收集】那些神器级别的BT磁力搜索网站
- 【网络编程】epoll边缘触发(ET模式)
- 机器学习入门学习笔记:(2.4)线性判别分析理论推导
- BZOJ 2958: 序列染色 && BZOJ 3193: [JLOI2013]地形生成 —— 肆虐的DP
- hdu 3342 Legal or Not 拓扑排序学习整理
- dtree树案例
- Top 10 algorithms in data mining
- Unity_通讯案例_TCP_怎样导入Unity中
- 如何自定义View将图片设置成圆形
- java容器的学习
- 查出来该字段重复2次以上的列 HAVING COUNT(*) > 1
- 日历表