2022/3/6 DP专场总结

A.Common Subsequence

  • 一道LCS的板子题……
AC code
#include<iostream>
#include<cstring>
#include<cmath>
#include<ios>
#include<sstream>
using namespace std;

string a,b;
int f[2005][1005];

int main(){
	while(cin>>a){
		cin>>b;
		int la=a.size(),lb=b.size();
		for(int i=0;i<=2e3;++i)
			for(int j=0;j<=1e3;++j)
				f[i][j]=0;
		for(int i=1;i<=la;++i){
			for(int j=1;j<=lb;++j){
				f[i][j]=max(f[i-1][j],f[i][j-1]);
				if(a[i-1]==b[j-1])
					f[i][j]=max(f[i][j],f[i-1][j-1]+1);
			}
		}
		printf("%d\n",f[la][lb]);
	}
	return 0;
}

B.Help Jimmy

  • 关于这道题,我不太明白我当时是怎么想出那么奇妙的方法的;

  • 正解思路:
    根据平台的高度来DP。由于我们可知,每块平台只有两种可能,就是从左端点落下和从右端点落下,所以我们设一个数组 \(f[n][2]\) 来记录分别从每块平台左右两端落下时的最小时间;
    对原始的平台按高度排序后,从低往高依次DP即可;
    从每一个点落下,至多到达一个平台,所以找到第一个可以落下的平台时无论如何这一个端点都没有另一种可能了;

  • 要注意落下的距离是否在 \(h_{max}\) 以内;

AC code
#include<iostream>
#include<algorithm>
#include<cmath>
#include<exception>
#include<cstring>
using namespace std;

const int d=2e4;

int t;
int n,x,y,Max;
int f[1005][2];

struct memr{
	int x1,x2,h;
}z[1005];

bool cmp(memr a,memr b){
	return a.h<b.h;
}

int main(){
	scanf("%d",&t);
	while(t--){
		memset(f,0x3f,sizeof(f));
		scanf("%d%d%d%d",&n,&x,&y,&Max);
		x+=d;
		for(int i=1;i<=n;++i){
			scanf("%d%d%d",&z[i].x1,&z[i].x2,&z[i].h);
			z[i].x1+=d,z[i].x2+=d;
		}
		z[++n].h=y,z[n].x1=z[n].x2=x;
		sort(z+1,z+n+1,cmp);
		f[0][0]=f[0][1]=0;
		for(int i=1;i<=n;++i){
			bool sf[2]={0,0};
			for(int j=i-1;j>-1;--j){
				if(sf[0] && sf[1]) break;
				if(z[i].h-z[j].h>Max) break;
				if(j==0){
					f[i][0]=(!sf[0])?z[i].h:f[i][0];
					f[i][1]=(!sf[1])?z[i].h:f[i][1];
					break;
				}
				if(!sf[0]){
					if(z[j].x1<=z[i].x1 && z[i].x1<=z[j].x2){
						sf[0]=1;
						if(z[i].h-z[j].h<=Max){
							f[i][0]=min(f[i][0],f[j][0]+z[i].h-z[j].h+z[i].x1-z[j].x1);
							f[i][0]=min(f[i][0],f[j][1]+z[i].h-z[j].h+z[j].x2-z[i].x1);
						}
					}
				}
				if(!sf[1]){
					if(z[j].x1<=z[i].x2 && z[i].x2<=z[j].x2){
						sf[1]=1;
						if(z[i].h-z[j].h<=Max){
							f[i][1]=min(f[i][1],f[j][0]+z[i].h-z[j].h+z[i].x2-z[j].x1);
							f[i][1]=min(f[i][1],f[j][1]+z[i].h-z[j].h+z[j].x2-z[i].x2);
						}
					}
				}
			}
		}
		printf("%d\n",min(f[n][0],f[n][1]));
	}
	return 0;
} 

C.Treats for the Cows

  • 区间DP,设 \(f[i][j]\) 表示还剩下起点为 \(i\) 终点为 \(j\) 的一段时最大可能的取值。

  • 不要忘记统计答案时加上 \(a_i×n\) 即最后一个点的贡献;

AC code
#include<iostream>
#include<algorithm>
#include<cmath>
#include<exception>
#include<cstring>
using namespace std;

int n;
int a[2005];
int f[2005][2005];

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		scanf("%d",&a[i]);
	for(int l=n-1,v=1;l;--l,++v){
		for(int s=1;s+l-1<=n;++s){
			int e=s+l-1;
			f[s][e]=max(f[s][e],f[s-1][e]+v*a[s-1]);
			f[s][e]=max(f[s][e],f[s][e+1]+v*a[e+1]);
//			printf("%d %d %d\n",s,e,f[s][e]);
		}
	}
	int ans=0;
	for(int i=1;i<=n;++i)
		ans=max(ans,f[i][i]+a[i]*n);
	printf("%d",ans);
	return 0;
} 

D.Milking Time

  • 按照开始时间排序,设 \(f_i\) 表示在第 \(i\) 个区间时能取到的最大值;
    添加一个最后的节点,起点为 \(n+r\);
    从后往前更新,状态转移为如果在当前区间要取的情况下,某一个后面的区间可以取,那么方程为 \(f_i=\max(f_i,f_j+{eff}_i)\);
AC code
#include<iostream>
#include<algorithm>
#include<cmath>
#include<exception>
#include<cstring>
using namespace std;

const int M=1e3+10;

int n,m,r;
int f[M];

struct memr{
	int st,ed;
	int eff;
}work[M];

bool cmp(memr _,memr __){
	return (_.st==__.st)?_.ed<__.ed:_.st<__.st;
}

int main(){
	scanf("%d%d%d",&n,&m,&r);
	for(int i=1;i<=m;++i)
		scanf("%d%d%d",&work[i].st,&work[i].ed,&work[i].eff);
	work[0].st=work[0].ed=0;
	work[++m].st=n+r;
	sort(work+1,work+m+1,cmp);
	for(int i=m;i>=0;--i){
		for(int j=i+1;j<=m;++j){
			if(work[j].st>=work[i].ed+r){
				f[i]=max(f[i],f[j]+work[i].eff);
//				printf("%d %d %d\n",i,j,f[i]);
			}
		}
	}
	int ans=0;
	for(int i=0;i<=m;++i)
		ans=max(ans,f[i]);
	printf("%d",ans);
	return 0;
} 

E.Making the Grade

  • 时隔一整个月才改……
AC code
#include<iostream>
#include<algorithm>
#include<cmath>
#include<exception>
#include<cstring>
using namespace std;

int n;
int a[2005],b[2005];
int f[2005][2005];

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d",&a[i]);
		b[i]=a[i];
	}
	sort(b+1,b+n+1);
	for(int i=1;i<=n;++i)
		f[0][i]=abs(a[1]-b[i]);
	int mn;
	for(int i=1;i<=n;++i){
		mn=f[i-1][1];
		for(int j=1;j<=n;++j){
			mn=min(mn,f[i-1][j]);
			f[i][j]=mn+abs(a[i]-b[j]);
		}
	}
	int ans=INT_MAX;
	for(int i=1;i<=n;++i)
		ans=min(ans,f[n][i]);
	printf("%d",ans);
	return 0;
} 
posted @ 2022-03-07 17:17  Star_LIcsAy  阅读(58)  评论(0)    收藏  举报