2019HDU多校第一场1001 BLANK (DP)

题意:构造一个长度为n(n<=10)的序列,其中的值域为{0,1,2,3}存在m个限制条件,表示为 l r x意义为[L,R]区间里最多能有x个不同的数字,计算序列构造方案数

思路

1.首先考虑最暴力的做法,直接dfs暴力构造,碰到区间的右端点就开始判断当前构造是否满足,如果不满足就回溯,很显然,复杂度爆炸O(4^n)

2.考虑怎么优化暴力算法,从(n<=100)不难猜出这是一个dp,考虑这种字符串构造形式的dp,肯定是一位一位有序构造,所以dp肯定是有序地扫一遍,所以进入了如何定义状态的阶段,我们注意到,一个区间里面数的种类的不同,只与当前点分别和最近的{0,1,2,3}的距离有关,如果在限制区间里面则种类+1,反之亦然。所以我们不难想到可以定义出状态dp[i][j][k][t][pos],表示{0,1,2,3}在Pos位置之前离pos最近分别在i,j,k,t,这样我们得出状态转移方程有(分别为填0,1,2,3)

dp[i][j][k][pos][pos]+=dp[i][j][k][t][pos-1]

dp[i][pos][k][t][pos]+=dp[i][j][k][t][pos-1]

dp[i][pos][k][t][pos]+=dp[i][j][k][t][pos-1]

dp[pos][j][k][t][pos]+=dp[i][j][k][t][pos-1]

我们可以得出,时间复杂度\(O(n^5)\)空间复杂度\(O(n^5)\)两者都不行,所以我们需要考虑如何优化,从状态转移方程中我们可以看到在5维中总有一对pos是相同的,所以这一维可以不用占时间复杂度和空间复杂度,并且可以用数组滚动,所以空间复杂度可以为\(O(n^3)\),时间复杂度为\(O(n^4)\)至此,已经满足题意了

但是我们试图对以上状态转移进行优化时,我们会发现pos到底和哪一位一样?这很难处理。因为pos既代表了一位数的位数又代表了当前位置,这样如何表达呢?我们思考一下,pos相对于i,j,k有什么性质?pos每次都是最大的,同时填{0,1,2,3}我们并不关心他的具体取值,只关系他的分布,所以取什么值都是对称的,例如0,1,2,3如果满足条件,那么3,2,1,0也一定满足条件,所以我们可不可以仅从分布位置的大小关系入手?设置i<j<k<t那么转移就变成了

dp[i][j][pos][now]+=dp[i][j][k][pre]

dp[i][k][pos-1][now]+=dp[i][j][k][pre]

dp[j][k][pos-1][now]+=dp[i][j][k][pre]

dp[i][j][pos-1][now]+=dp[i][j][k][pre]

我们分别解释第一个状态和第二个状态。首先我们可以知道,上一个状态最大的肯定是pos-1也就是当前状态的k=pos-1因为当前位置是pos,第一个状态表示把pos位置填上和k相同的值。而第二个状态表示把pos填上和j相同的值,那么上一个k可以就是pos-1变成了次大值,最大值变成了pos也就是当前填的值。(每个状态里面都隐藏了当前的最大t一定是位置,以此好理解转移)

这样我们就还剩下了限制条件,我们只要把每个限制条件放进以右端点值为key的数组中,每次dp完一个位置后,看满不满足限制条件,不满足就置为0即可,因为状态的良好定义,使得判断极为简单

思考

碰到构造计数类dp的时候,通常是从左到右dp,我们首先考虑如何判断限制条件,再以此设计状态,状态的定义要可以很方便得判断出是否满足限制条件,对于不满足限制条件的状态,我们可以在dp中使dp数组置0来阻止其继续递推。设计状态的时候从最暴力逐渐优化,思路不能乱,不能乱了方寸,否则dp的难度一高,状态一复杂,就会导致心态爆炸,代码写炸。

Reference

https://blog.csdn.net/Ratina/article/details/97237438 顺便%一下这位大佬

#include<bits/stdc++.h>
#include<vector>
#include<algorithm>
using namespace std;
#define pb push_back
#define F first
#define S second
#define mkp make_pair
const int mod=998244353;
const int maxn=100+4;
int dp[maxn][maxn][maxn][2];
vector< pair<pair<int,int>,int> >v[maxn];
int t,n,m;
int ans=0;
int add(int x,int y){
return (1ll*x+y)%mod;
}
int main(){
scanf("%d",&t);
while(t--){
ans=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
v[i].clear();
for(int i=0;i<m;i++){
int l,r,x;
scanf("%d%d%d",&l,&r,&x);
v[r].pb(mkp(mkp(l,r),x));
} for(int k=0;k<n;k++)
for(int j=0;j<max(1,k);j++)
for(int i=0;i<max(1,j);i++)dp[i][j][k][1]=dp[i][j][k][0]=0;
dp[0][0][0][0]=1; int now=1;
for(int pos=1;pos<=n;pos++){
for(int k=0;k<max(pos-1,1);k++){
for(int j=0;j<max(1,k);j++){
for(int i=0;i<max(1,j);i++){
dp[i][j][k][now]=add(dp[i][j][k][now],dp[i][j][k][now^1]);
dp[i][j][pos-1][now]=add(dp[i][j][pos-1][now],dp[i][j][k][now^1]);
dp[j][k][pos-1][now]=add(dp[j][k][pos-1][now],dp[i][j][k][now^1]);
dp[i][k][pos-1][now]=add(dp[i][k][pos-1][now],dp[i][j][k][now^1]);
dp[i][j][k][now^1]=0; }
}
}
for(int k=0;k<max(pos,1);k++){
for(int j=0;j<max(1,k);j++){
for(int i=0;i<max(1,j);i++){
for(auto&p:v[pos]){
if((i>=p.F.F)+(j>=p.F.F)+(k>=p.F.F)+1!=p.S){
dp[i][j][k][now]=0;
}
} }
}
}
now^=1;
}
for(int k=0;k<max(1,n);k++){
for(int j=0;j<max(1,k);j++){
for(int i=0;i<max(1,j);i++){
ans=add(ans,dp[i][j][k][now^1]);
}
}
}
printf("%d\n",ans); } return 0;
}

2019HDU多校第一场1001 BLANK (DP)(HDU6578)的更多相关文章

  1. HDU6578 2019HDU多校训练赛第一场 1001 (dp)

    HDU6578 2019HDU多校训练赛第一场 1001 (dp) 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6578 题意: 你有n个空需要去填,有 ...

  2. 2019HDU多校第一场 BLANK DP

    题意:有四种数字,现在有若干个限制条件:每个区间中不同的数字种类必须是多少种,问合法的方案数. 思路: 定义 dp[i][j][k][t] 代表填完前 t 个位置后,{0,1,2,3} 这 4 个数字 ...

  3. [2019HDU多校第一场][HDU 6578][A. Blank]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6578 题目大意:长度为\(n\)的数组要求分别填入\(\{0,1,2,3\}\)四个数中的任意一个,有 ...

  4. HDU6298 Maximum Multiple (多校第一场1001)

    Maximum Multiple Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  5. 2019牛客多校第一场 E-ABBA(dp)

    ABBA 题目传送门 解题思路 用dp[i][j]来表示前i+j个字符中,有i个A和j个B的合法情况个数.我们可以让前n个A作为AB的A,因为如果我们用后面的A作为AB的A,我们一定也可以让前面的A对 ...

  6. 2019牛客多校第一场E ABBA dp

    ABBA dp 题意 给出2(N+M)个AB字符,问能构造出N个AB子序列和M个BA子序列组成的2*(n+m)的序列种类有多少 思路 碰到计数构造类的题目,首先要去找到判断合法性的条件,即什么情况下合 ...

  7. 2018牛客多校第一场 E-Removal【dp】

    题目链接:戳这里 转自:戳这里 题意:长度为n的序列,删掉m个数字后有多少种不同的序列.n<=10^5,m<=10. 题解:dp[i][j]表示加入第i个数字后,总共删掉j个数字时,有多少 ...

  8. [2019HDU多校第一场][HDU 6580][C. Milk]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6580 题目大意:\(n\times m\)大小的方格上有\(k\)瓶水,喝完每瓶水都需要一定的时间.初 ...

  9. [2019HDU多校第一场][HDU 6584][G. Meteor]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6584 题目大意:求所有满足\(0<\frac{p}{q}\leq1, gcd(p,q)=1,p\ ...

随机推荐

  1. linux 搭建python虚拟环境

    requirements.txt 包含paramiko,pysfp.setuptools,适用python版本3.6.6+ 前提编译安装python wget wget https://www.pyt ...

  2. mui 时间选择器和上传图片

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <meta name= ...

  3. [SNOI2017]炸弹[线段树优化建图]

    [SNOI2017]炸弹 线段树优化建图,然后跑一边tarjan把点全部缩起来,炸一次肯定是有连锁反应的所以整个连通块都一样-于是就可以发现有些是只有单向边的不能忘记更新,没了. #include & ...

  4. beego——view 模板语法

    一.基本语法 go统一使用{{和}}作为左右标签,没有其它的标签符号. 使用"."来访问当前位置的上下文,使用"$"来引用当前模板根级的上下文,使用$var来访 ...

  5. scala-匹配序列和元组

    scala的模式匹配极其强大,其中有一种用法是用case语句匹配序列和元组. 放码过来: def parse(x: Any): String = x match { case List(0, _, _ ...

  6. AC认证技术

    一.认证方式 Dkey认证(数字密钥认证) 1)免认证key,形同usb,插入即通过认证 2)免审计key,也是上网不被记录审计. 单点登录 登录了某点,其他点都能访问:例如登录了支付宝淘宝就不用登录 ...

  7. 剑指offer 15.链表反转

    15.链表反转 题目描述 输入一个链表,反转链表后,输出新链表的表头. PHead,pre, next分别指向当前结点, 前一个结点, 后一个结点,每次迭代先更新当前结点的指针,记录下个结点的指向,转 ...

  8. 题解【洛谷P1896】[SCOI2005]互不侵犯

    题面 棋盘类状压 DP 经典题. 我们考虑设 \(dp_{i,j,s}\) 表示前 \(i\) 行已经摆了 \(j\) 个国王,且第 \(i\) 行国王摆放的状态为 \(s\) 的合法方案数. 转移的 ...

  9. 记录 Docker 的学习过程 (安装基础篇)

    docker 通过内核来实现 特点是效率高 1. centos7 三台(推荐2c 4g 最低 1c1g)2. 关闭防火墙 selinux3. 做好主机名解析,三台能互相ping通主机名host参考文件 ...

  10. ASP.NET MVC 简介(附VS2019和VSCode版示例)

    MVC可以理解为一种思想,应用在web应用程序的架构上. ASP.NET MVC的核心类是实现了IHttpHandler接口的MVCHandler,它的底层仍然是HttpHandler.HttpReq ...