2020-11-28NOIP模拟T1【区间DP】

这道题一开始被卡贪心思路然后发现大样例都过不了良心大样例
对于一个数列 2   4   2   3   4   3 2\ 4\ 2\ 3\ 4\ 3 2 4 2 3 4 3,贪心思路只取 4 4 4,但是显然取 2   3 2\ 3 2 3更优。
正解:区间 D P DP DP,看到对于区间操作求最值,但又不是维护一些最大值最小值之类的区间性质的时候,就可以联想一下区间 D P DP DP的方法。
具体做法:令 f [ i ] [ j ] f[i][j] f[i][j]表示区间 i ∼ j i\sim j ij能取到的最大值,按区间长度从小到大转移。
f [ i ] [ j ] = m a x k ( f [ i ] [ k ] + f [ k + 1 ] [ j ] ) f[i][j]=max_k(f[i][k]+f[k+1][j]) f[i][j]=maxk(f[i][k]+f[k+1][j])
如果有 a [ i ] = = a [ j ] a[i]==a[j] a[i]==a[j],再判断此时要不要取这个数: f [ i ] [ j ] = m a x ( f [ i ] [ j ] , a [ i ] + f [ i + 1 ] [ j − 1 ] ) f[i][j]=max(f[i][j],a[i]+f[i+1][j-1]) f[i][j]=max(f[i][j],a[i]+f[i+1][j1])
时间复杂度 O ( n 3 ) O(n^3) O(n3),但常数 1 6 \frac {1}{6} 61,可以通过此题。


D P   y y d s ! DP\ yyds! DP yyds
动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。-百度百科
然而这也是动态规划的本质,递推出所有可行解然后找到最优值,领略到这一点之后,一切 D P DP DP都会变得了然起来。
不知道为什么总会有一些奇奇怪怪的话戳到我让我搞明白一些事情。


附上考场代码(还有我之前错误的贪心思路来着)

#include 
#include 
using namespace std;
const int N=505;
int n,a[N],cnt=0;
int f[N][N];
int que[N];
int tot=0,tmp,tmp1,tmp2,maxx;
//inline void del(){
//	tmp=tot;maxx=que[tmp];
//	for(int i=tmp-1;i>=1;--i){
//		if(que[i]>maxx) return;
//		if(que[i]==maxx){
//			cnt+=que[i];
//			tot=i-1;
//			return;
//		}
//	}
//}
inline int read(){
	int cnt=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}
	while(isdigit(c)){cnt=(cnt<<1)+(cnt<<3)+(c^48);c=getchar();}
	return cnt*f;
}
signed main(){
	freopen("card.in","r",stdin);
	freopen("card.out","w",stdout);
	n=read();
	memset(f,0,sizeof(f));
	for(int i=1;i<=n;++i) a[i]=read();
	for(int i=1;i<=n;++i){
		tmp1=n-i;
		for(int j=1;j<=tmp1;++j){
			tmp2=j+i;
			for(int k=j;k<=tmp2;++k){
				f[j][tmp2]=max(f[j][tmp2],f[j][k]+f[k+1][tmp2]);
				if(a[j]==a[tmp2]) f[j][tmp2]=max(f[j][tmp2],a[j]+f[j+1][tmp2-1]);
			}
		}
	}
//	for(int i=1;i<=n;++i){
//		que[++tot]=a[i];
//		del();
//	}
	printf("%d\n",f[1][n]);
//	cerr<<(double)clock()<
	return 0;
}

你可能感兴趣的:(动态规划,联赛模拟)