区间dp

每日dp

1.小Q与彼岸花

题目链接
题意:小 Q 的院子里种了 n 朵彼岸花,其中第 i 朵的彼岸花的美丽值为 a i,彼岸花按照编号从小到大从左向右排成了一排。现在小 Q 有 m 个问题,他每次会给出一个区间 [ l , r ],他想在编号属于区间 [ l , r ] 的彼岸花中选出两朵花,使得 a i ⨁ a j ( ⨁ 表示按位异或操作) 的值最大(如果只能选出一朵花请直接输出 0)。
在这里插入图片描述
思路:可以发现关于每一个输入的 l,r大小不超过5e3,那么如果m次查询前直接求出每一个dp[ l ][ r ]的值,就肯定不会超时啦,dp[ l ][ r ]是该区间的可以异或的最大值,大概想象一下这个区间一定是dp[ 1 ][ n ]是最大的值,那要怎么样可以从其他的状态推到这个最大的状态呢。举个栗子:假设要求(6,16)的区间,这个区间和别的区间最独特的区别就是多了一个a6^ a16的状态,根据这个我们可以试一下周围的状态(7,16)这个区间,发现竟然漏掉状态了 ……少了(a6^ a7,a6^ a8,a6^ a9……a6^ a15)这些状态,需要打上他们的补丁,(而有a6^ a15这个状态最小的区间能包含这些的就是dp[6][15])然后我们就可以愉快的推式子了~状态转移方程:dp[ i ][ j ]=max(a[ i ]^ a[ j ],max(dp[ i +1][ j ],dp[ i ][ j -1]));根据转移方程发现 i 要从后往前推,j 要从前往后推,且 i 要比 j 小。
发现这本质上就是一个数塔问题(当n=4时的状态递推)

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e3+100;
int dp[maxn][maxn],n,m,a[maxn];
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=n;i>=1;i--){
		for(int  j=i;j<=n;j++){
			dp[i][j]=max(a[i]^a[j],max(dp[i+1][j],dp[i][j-1]));
		}
	}
	for(int i=1;i<=m;i++){
		int l,r;
		cin>>l>>r;
		cout<<dp[l][r]<<endl;
	}
	return 0;
}

2.小小粉刷匠

题目链接
题意:“lalala,我是一个快乐的粉刷匠”,小名一边快活地唱着歌,一边开心地刷着墙",兴致突然被打断,“小名,你今天如果刷不完这一栋楼的墙,那么你就等着被炒鱿鱼吧”,老板声嘶力竭的吼着。苦恼的小名因为不想被炒鱿鱼,所以希望尽量快地刷完墙,由于他本人的数学基础很差,他现在请你来帮助他计算最少完成每一堵墙需要刷多少次。每一面墙有n个段,对于每个段指定一个目标颜色ci。刚开始的时候所有的墙壁为白色,我们现在有一个刷子,刷子长度为k,刷子每次可以选择一种颜色,然后选择段数为(1~k)连续的墙段刷成选择的一种颜色。我们现在想要知道,为了把墙变成目标颜色,最少刷多少次(保证指定的目标颜色一定不为白色)。
在这里插入图片描述
解题思路:想象每次刷子会刷一段,区间dp非常合适,数据范围也非常合适,先定义dp[ l ][ r ]是该区间内的最小的需要被刷的数,dp[ l ][ r ]的集合是区间里面的所有能合并成出dp[ l ][ r ]的方案数。那么现在就要推这个状态转移的方程了。把这个区间先写下来,是从l , l+1 , l+2 , … , w ,…, r-1 ,r ;写的时候只考虑最后一步,一段区间进行合并一定是左边的区间加上右边的区间,这样然后就要在区间里枚举分割点,里面的区间都已经是最优解了,但是两端区间加起来构成的不一定是最优解因为默认里面的两个分隔点不可以一起刷,所以这样子的方程式是dp[ l ][ r ]=min(dp[ l ][ r ],dp[ l ][ w ]+dp[ w+1 ][ r ]),另外那把刷子的长度可不要忽略了,因为里面的分割点都会被枚举到,一段区间就只剩了首尾没有进行过判断。要想判断首尾能否用刷子一次刷掉,就要判断len<=k这个条件是不是可以符合,那么就要判断a[ l ]==a[ r ]这个条件。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e2+100;
const int INF=0x3f3f3f3f;
int dp[maxn][maxn],a[maxn];
int n,k;
int main(){
	cin>>n>>k;
	memset(dp,INF,sizeof(dp));
	for(int i=1;i<=n;i++) cin>>a[i],dp[i][i]=1;
	for(int len=2;len<=n;len++){
		for(int i=1;i<=n;i++){
			int j=i+len-1;
			if(j>n) break;
			for(int q=i;q<j;q++){
				if(len<=k&&a[i]==a[j]){
					dp[i][j]=min(dp[i+1][j],dp[i][j-1]);
				}
				else {
					dp[i][j]=min(dp[i][q]+dp[q+1][j],dp[i][j]);
				}
			}
		}
	}
	cout<<dp[1][n]<<endl;
	return  0;
}

3.玩具取名

题目链接
题意:某人有一套玩具,并想法给玩具命名。首先他选择WING四个字母中的任意一个字母作为玩具的基本名字。然后他会根据自己的喜好,将名字中任意一个字母用“WING”中任意两个字母代替,使得自己的名字能够扩充得很长。
现在,他想请你猜猜某一个很长的名字,最初可能是由哪几个字母变形过来的。
在这里插入图片描述
解题思路:通过观察名字的合并方式,发现又是左边的加右边的可以合并出一个新的区间,用flag[l][r][x]代表用l和r是否可以合并出x,用flag来反映可以合并成一个字母的所有条件,然后用dp区间一步步从长度开始推进,判断所有可以合成的状态,区间dp板子题。

#include<bits/stdc++.h>
using namespace std;
const int maxn=300;
int dp[maxn][maxn][10];
bool flag[maxn][maxn][10];
int m,n;
int change(char c){
	if(c=='W') return 1;
	else if(c=='I') return 2;
	else if(c=='N') return 3;
	else return 4;
}
void qwq(int x,int a){
	for(int i=1;i<=x;i++){
		char c1,c2;cin>>c1>>c2;
		flag[change(c1)][change(c2)][a]=1;
    }    
}
void atota(int i,int k,int j){
	for(int p=1;p<=4;p++){
		for(int l=1;l<=4;l++){
		   if(dp[i][k][p]!=0&&dp[k+1][j][l]!=0){
		  	    for(int o=1;o<=4;o++){
                    if(flag[dp[i][k][p]][dp[k+1][j][l]][o]==1){
               	    dp[i][j][o]=o;                              	
				    }					   		
			    }
		    }
	    }
	}
}
int main(){
	int w,i,n,g;
	cin>>w>>i>>n>>g;
    qwq(w,1),qwq(i,2),qwq(n,3),qwq(g,4);
	string s;
	cin>>s;
	int m=s.size();
	for(int i=1;i<=m;i++){
		dp[i][i][change(s[i-1])]=change(s[i-1]);
	}
	for(int len=2;len<=m;len++){
		for(int i=1;i<=m;i++){
			int j=len+i-1;
			if(j>m) break;
			for(int k=i;k<j;k++){
            atota(i,k,j);
			}
		}
	}
	int flag1=0;
    if(dp[1][m][1]) flag1=1,cout<<"W";
 	if(dp[1][m][2]) flag1=1,cout<<"I";
	if(dp[1][m][3]) flag1=1,cout<<"N";
	if(dp[1][m][4]) flag1=1,cout<<"G"; 
 	if(flag1==0) cout<<"The name is wrong!"<<endl;
 	else cout<<endl;
	return 0;
}

4.you are the one

题目链接
题意:像《非诚勿扰》这样的电视节目一直很受欢迎。为了满足单身男孩的需求,我们自己举办了这场演出。演出在小礼堂里举行,因此吸引了许多男孩和女孩。现在有n个男孩报名参加。一开始,n个男孩站成一排,一个接一个地走上舞台。然而,导演突然知道,每个男孩都有一个价值观,如果男孩是第k个上台的,他的不快乐就会是(k-1)*D,因为他要等(k-1)人。幸运的是,小厅里有一个暗室,所以导演可以暂时把男孩放进暗室,让他后面的男孩在他前面上台。因为暗室很窄,最先进入暗室的男孩必须最后离开。导演想在暗室里改变男孩们的顺序,所以对不快乐的总结最少。你能帮他吗?
思路:这里的暗室是一个栈堆,男孩们会进这个栈堆去改变自己的顺序。如果可以随意排列男孩们的顺序,那么这道题用贪心就可以求解,而这道题需要用栈堆来限制排列顺序,那么我们要求的就是合法的栈堆排列顺序下的最小值。这显然不能用贪心来求解,且要考虑区间里的每个元素的顺序,所以用区间dp来求解。确定dp[ l ][ r ]是该区间里的排列的最小值。有顺序进栈的排列,有个重要的性质,当第一个元素是第k个出栈时,那么区间(2,k)的元素一定比第一个元素先出栈,(k+1,n)的元素一定比第一个元素后出栈,这样就可以将一个大区间划分成两个小区间了, 要枚举区间里第一个元素的出栈顺序,再不断递归到小区间里的的最小区间值,就可以求解啦。

#include<bits/stdc++.h>
using namespace std;
const int maxn=120;
#define INF 0xffffff
int dp[maxn][maxn],sum[maxn],a[maxn];
int main(){
	int t;cin>>t;
	while(t--){
		int n;cin>>n;
		for(int i=1;i<=n;i++) sum[i]=0;
		for(int i=1;i<=n;i++){
			for(int j=i+1;j<=n;j++){
				dp[i][j]=INF;
			}
		}
		for(int i=1;i<=n;i++) cin>>a[i],sum[i]=sum[i-1]+a[i];
	
		for(int len=2;len<=n;len++){
			for(int i=1;i<=n;i++){
				int j=i+len-1;
				if(j>n) break;
				for(int k=i;k<=j;k++){
					dp[i][j]=min(dp[i][j],a[i]*(k-i)+dp[i+1][k]+dp[k+1][j]+(sum[j]-sum[k])*(k-i+1));
				}
			}
		}
		cout<<dp[1][n]<<endl;
		
	}
	return 0;
} 
已标记关键词 清除标记
相关推荐
程序员的必经之路! 【限时优惠】 现在下单,还享四重好礼: 1、教学课件免费下载 2、课程案例代码免费下载 3、专属VIP学员群免费答疑 4、下单还送800元编程大礼包 【超实用课程内容】  根据《2019-2020年中国开发者调查报告》显示,超83%的开发者都在使用MySQL数据库。使用量大同时,掌握MySQL早已是运维、DBA的必备技能,甚至部分IT开发岗位也要求对数据库使用和原理有深入的了解和掌握。 学习编程,你可能会犹豫选择 C++ 还是 Java;入门数据科学,你可能会纠结于选择 Python 还是 R;但无论如何, MySQL 都是 IT 从业人员不可或缺的技能!   套餐中一共包含2门MySQL数据库必学的核心课程(共98课时)   课程1:《MySQL数据库从入门到实战应用》   课程2:《高性能MySQL实战课》   【哪些人适合学习这门课程?】  1)平时只接触了语言基础,并未学习任何数据库知识的人;  2)对MySQL掌握程度薄弱的人,课程可以让你更好发挥MySQL最佳性能; 3)想修炼更好的MySQL内功,工作中遇到高并发场景可以游刃有余; 4)被面试官打破沙锅问到底的问题问到怀疑人生的应聘者。 【课程主要讲哪些内容?】 课程一:《MySQL数据库从入门到实战应用》 主要从基础篇,SQL语言篇、MySQL进阶篇三个角度展开讲解,帮助大家更加高效的管理MySQL数据库。 课程二:《高性能MySQL实战课》主要从高可用篇、MySQL8.0新特性篇,性能优化篇,面试篇四个角度展开讲解,帮助大家发挥MySQL的最佳性能的优化方法,掌握如何处理海量业务数据和高并发请求 【你能收获到什么?】  1.基础再提高,针对MySQL核心知识点学透,用对; 2.能力再提高,日常工作中的代码换新貌,不怕问题; 3.面试再加分,巴不得面试官打破沙锅问到底,竞争力MAX。 【课程如何观看?】  1、登录CSDN学院 APP 在我的课程中进行学习; 2、移动端:CSDN 学院APP(注意不是CSDN APP哦)  本课程为录播课,课程永久有效观看时长 【资料开放】 课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优化。  下载方式:电脑登录课程观看页面,点击右侧课件,可进行课程资料的打包下载。
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页