DP套DP
DP套DP,就是将内层DP的结果作为外层DP的状态进行DP的方法。
[BZOJ3864]Hero meet devil
对做LCS的DP数组差分后状压,预处理出转移数组,然后直接转移即可。
tr[S][k]表示当前差分状压后的状态为S,加入字符k(k为ACGT中一个)后会转移到什么状态。
f[i][S]表示串已构造到第i位,和模式串的匹配状态差分后为S,的方案数。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=,M=,mod=1e9+;
int T,n,m,d[],g[],ans[N],tr[M][],cnt[M],f[][M];
char s[],c[]="ACGT"; int main(){
freopen("bzoj3864.in","r",stdin);
freopen("bzoj3864.out","w",stdout);
for (scanf("%d",&T); T--; ){
scanf("%s%d",s+,&m); n=strlen(s+);
for (int S=; S<<<n; S++){
if (S) cnt[S]=cnt[S^(S&-S)]+;
rep(i,,n-) d[i+]=d[i]+((S>>i)&);
rep(k,,){
rep(i,,n) g[i]=max(max(d[i],g[i-]),(c[k]==s[i])?d[i-]+:);
tr[S][k]=;
rep(i,,n-) if (g[i+]-g[i]) tr[S][k]|=<<i;
}
}
memset(ans,,sizeof(ans)); memset(f,,sizeof(f)); f[][]=;
rep(i,,m){
int v=i&,u=v^; memset(f[v],,sizeof(f[v]));
for (int S=; S<<<n; S++)
rep(k,,) f[v][tr[S][k]]=(f[v][tr[S][k]]+f[u][S])%mod;
}
for (int S=; S<<<n; S++) ans[cnt[S]]=(ans[cnt[S]]+f[m&][S])%mod;
rep(i,,n) printf("%d\n",ans[i]);
}
return ;
}
[BZOJ5336][TJOI2018]party
同上题,多加一维0/1/2表示末尾和'NOI'匹配到第几位即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=,M=,mod=1e9+;
int T,n,m,d[],g[],ans[N],tr[M][],cnt[M],f[][M][];
char s[],c[]="NOI"; int main(){
freopen("bzoj5336.in","r",stdin);
freopen("bzoj5336.out","w",stdout);
scanf("%d%d%s",&m,&n,s+);
for (int S=; S<<<n; S++){
if (S) cnt[S]=cnt[S^(S&-S)]+;
rep(i,,n-) d[i+]=d[i]+((S>>i)&);
rep(k,,){
rep(i,,n) g[i]=max(max(d[i],g[i-]),(c[k]==s[i])?d[i-]+:);
tr[S][k]=;
rep(i,,n-) if (g[i+]-g[i]) tr[S][k]|=<<i;
}
}
f[][][]=;
rep(i,,m){
int v=i&,u=v^; memset(f[v],,sizeof(f[v]));
for (int S=; S<<<n; S++) rep(l,,) if (f[u][S][l]){
rep(k,,){
int S1=tr[S][k],l1=l;
l1=(k==l) ? l1+ : ((!k)?:);
if (l1<) f[v][S1][l1]=(f[v][S1][l1]+f[u][S][l])%mod;
}
}
}
for (int S=; S<<<n; S++)
rep(i,,) ans[cnt[S]]=(ans[cnt[S]]+f[m&][S][i])%mod;
rep(i,,n) printf("%d\n",ans[i]);
return ;
}
[BZOJ3591]最长上升子序列
给出1~n的一个排列的一个最长上升子序列,求原排列可能的种类数。
考虑最长上升子序列$O(n\log n)$算法中使用的单调队列,将单调队列中的数组成的集合作为状态DP。
f[S]表示当前状态S的方案数,其中S是一个三进制数,第i位为0表示这个数尚未被选入数列,1表示选入数列但不在单调队列中,2表示在单调队列中。
对于每个状态,枚举下一个加入序列的数是什么来转移。可以先预处理减小常数。
具体细节可看代码注释,$O(2^n n^2+3^n n)$
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
using namespace std; const int N=,M=1.5e7;
int n,m,x,id[N],p[N],f[M];
bool flag[<<N][N];
int v[<<N][N],c[<<N],mx[<<N],s[<<N],ans=; int main(){
freopen("bzoj3591.in","r",stdin);
freopen("bzoj3591.out","w",stdout);
scanf("%d%d",&n,&m);
rep(i,,m) scanf("%d",&x),id[x-]=i;
p[]=; rep(i,,n) p[i]=p[i-]*;
for (int S=; S<(<<n); S++)//预处理出每个可能的状态转移,S为当前已经选进单调队列的集合,flag表示能否转移,v是转移到什么位置
rep(i,,n-){
if (S&(<<i)){ c[S]+=p[i]; mx[S]=max(mx[S],i); s[S]++; continue; }
//c:全1的三进制状态,mx:最大数,s:popcount
if (!id[i]) flag[S][i]=;
else{
int tot=;
rep(j,,n-) if (S&(<<j) && id[j]) tot++;
if (tot+==id[i]) flag[S][i]=;//满足在LIS中的位置为id[i]
}
int t=-,x=;
rep(j,,n-) if (S&(<<j)) x+=p[j];//S转三进制
for (int j=n-; j>i; j--) if (S&(<<j)) t=j;//找到集合中比i大的最小的数更新
if (~t) v[S][i]=x-p[t]+p[i]; else v[S][i]=x+p[i];
}
f[]=;
for (int x=; x<(<<n); x++)
for (int y=x; y> || (!y && !x); (!x) ? y-- : y=(y-)&x)//x为已在序列中的数的集合,y为在单调队列中数的集合
if (f[c[x]+c[y]]){
int t=c[x]+c[y];
for (int i=; s[y]==m ? i<mx[y] : i<n; i++)//枚举新加进序列的数(若单调队列长度已满则不能加入更大的数)
if (flag[x][i]) f[c[x]+p[i]+v[y][i]]+=f[t];//新加进序列的数一定也加进单调队列
if (x==(<<n)-) ans+=f[t];
}
printf("%d\n",ans);
return ;
}
DP套DP的更多相关文章
- bzoj 3864: Hero meet devil [dp套dp]
3864: Hero meet devil 题意: 给你一个只由AGCT组成的字符串S (|S| ≤ 15),对于每个0 ≤ .. ≤ |S|,问 有多少个只由AGCT组成的长度为m(1 ≤ m ≤ ...
- [模板] dp套dp && bzoj5336: [TJOI2018]party
Description Problem 5336. -- [TJOI2018]party Solution 神奇的dp套dp... 考虑lcs的转移方程: \[ lcs[i][j]=\begin{ca ...
- luogu 4158 粉刷匠 dp套dp
dp套dp 每个木板是个递推的dp,外部是个分组背包 #include<bits/stdc++.h> #define rep(i,x,y) for(register int i=x;i&l ...
- Codeforces 372B Counting Rectangles is Fun:dp套dp
题目链接:http://codeforces.com/problemset/problem/372/B 题意: 给你一个n*m的01矩阵(1 <= n,m <= 40). 然后有t组询问( ...
- 【BZOJ3864】Hero meet devil DP套DP
[BZOJ3864]Hero meet devil Description There is an old country and the king fell in love with a devil ...
- codeforces 979E(dp套dp)
题意: 有n个点,编号为1~n.有的点颜色是黑色,有的点颜色是白色,有的点的颜色待涂.你还可以连一些边,但这些边一定是从小编号连到大编号的点. 对于一个确定的图,我们去统计有多少条路径满足“该路径经过 ...
- dp 套 dp扯谈
1.[扯谈概念] \(dp\) 套 \(dp\) 其实也就是 \(dp\) . 这里就定义下面两个概念: 内层 \(dp\) 表示的是被套在里面的那个 \(dp\) 外层 \(dp\) 表示的是最外面 ...
- P4590-[TJOI2018]游园会【dp套dp】
正题 题目链接:https://www.luogu.com.cn/problem/P4590 题目大意 给出一个长度为\(m\)的字符串\(s\). 对于每个\(k\in[0,m]\)求有多少个长度为 ...
- 洛谷 P5279 - [ZJOI2019]麻将(dp 套 dp)
洛谷题面传送门 一道 dp 套 dp 的 immortal tea 首先考虑如何判断一套牌是否已经胡牌了,考虑 \(dp\).我们考虑将所有牌按权值大小从大到小排成一列,那我们设 \(dp_ ...
随机推荐
- bzoj4695 最假女选手
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4695 [题解] SegmentTree beats!(见jiry_2论文/营员交流) 考虑只 ...
- .NET FrameWork 中的 CTS
CTS:Common Type System 通用类型系统. 1.不仅可以把C#编译成.Net IL,还支持Basic.Python.Ruby等语言,甚至还支持Java.不同语言中的数据类型定义是不一 ...
- linux进程管理-定时定期执行任务
0.计划任务的命令: at 安排作业在某一时刻执行 batch 安排作业在系统负载不重时执行 crontab 安排周期性运行的作业 1.at命令用法: 安排命令或者多个命令在指定的时间运行一次 语法 ...
- Java中的return语句使用总结
Java中的return语句总是和方法有密切关系,return语句总是用在方法中,有两个作用,一个是返回方法指定类型的值(这个值总是确定的),一个是结束方法的执行(仅仅一个return语句). 在 ...
- centos7系统安装配置
下载centos7 iso镜像 电脑里面本来有ubuntu系统,直接在u盘做好启动盘安装即可,选择手动分区(忘了),将原本ubuntu系统分区压缩200G.系统不要选择最小化,选择gnome的图形界面 ...
- centos_7.1.1503_src_2
farstream02-0.2.3-3.el7.src.rpm 05-Jul-2014 12:59 1.2M fcoe-utils-1.0.29-9.el7.src.rpm 31-Mar-2015 ...
- pycharm模板参数
# -*- coding: utf-8 -*-# @Time : ${DATE} ${TIME}# @Author : cxa# @File : ${NAME}.py# @Software: ${PR ...
- 使用JMX工具远程监控tomcat配置
使用JMX工具远程监控tomcat,在tomcat启动时添加配置参数: -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.po ...
- (转)函数后面加const--C++ const成员函数
类的成员函数后面加 const,表明这个函数不会对这个类对象的数据成员(准确地说是非静态数据成员)作任何改变. 在设计类的时候,一个原则就是对于不改变数据成员的成员函数都要在后面加 const,而对于 ...
- [ Python ] 文件的读写操作
1. 文件读写操作 读写文件是最常见的 IO 操作, Python 内置了读写文件的函数.在磁盘上读写文件的功能是由操作系统提供的,所以读写文件是请求操作系统打开一个文件对象(通常称为文件描述符),然 ...