1. 程式人生 > 其它 >Component is missing template or render function

Component is missing template or render function

給定一個序列\(a_i\),每次可以刪除前\(3\)箇中的\(2\)個,代價為所刪兩數的\(a_i\)最大值;若數字個數小於\(3\),就一次刪完,代價同樣為\(a_i\)最大值。求刪掉所有數的最小代價以及方案。

\(n\le 1000,1\le a_i\le 10^6\)

Solution

這樣的刪數方式很特別,我們需要尋找一些性質。

從序列的形狀上看,沒有被刪的數應該是 一個單點+一個字尾,也可能只有一個字尾。

啥,你說咋看出來的?字尾顯然,單點多刪幾次就可以發現。

那不就很好dp了嗎。

\(f_{i,j}\)表示單點位置為\(i\),字尾左端點為\(j\)時,最小代價是多少。

刷表,討論刪掉前\(3\)

箇中的哪\(2\)個。

\(f_{i,j}\)可以貢獻到:

  • \(f_{i,j+2}\)
  • \(f_{j+1,j+1}\)
  • \(f_{j,j+2}\)

還要考慮只有字尾的情況,不妨設當\(i=j\)時,字尾為從\(i\)開始的區間。
\(f_{i,i}\)可以貢獻到

  • \(f_{i+2,i+2}\)
  • \(f_{i+1,i+3}\)
  • \(f_{i,i+3}\)

然後就是記錄方案。

程式碼:

#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
using namespace std;
inline int read(){
	int x=0,f=0;
	char ch=getchar();
	while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
	while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return f?-x:x;
}
typedef pair<int,int> pii;
const int N=1005;
int n,a[N],f[N][N],pre[N][N][2];
void upd(int x,int y,int i,int j,int val){
	//用f[i,j]更新f[x,y],val為轉移時的代價 
	if(f[x][y]>f[i][j]+val){
		f[x][y]=f[i][j]+val;
		pre[x][y][0]=i;
		pre[x][y][1]=j;
	}
}
int main(){
	n=read();
	for(int i=1;i<=n;++i) a[i]=read();
	memset(f,0x3f,sizeof(f));
	f[1][1]=0;
	for(int i=1;i<=n+2;++i){
		upd(i+2,i+2,i,i,max(a[i],a[i+1]));
		upd(i+1,i+3,i,i,max(a[i],a[i+2]));
		upd(i,i+3,i,i,max(a[i+1],a[i+2]));
		for(int j=i+1;j<=n+2;++j){
			upd(i,j+2,i,j,max(a[j],a[j+1]));
			upd(j+1,j+1,i,j,max(a[i],a[j]));
			upd(j,j+2,i,j,max(a[i],a[j+1])); 
		}
	}
	vector<pii>ans;
	int x,y;
	if(n&1) printf("%d\n",f[n+2][n+2]),x=y=n+2;
	else printf("%d\n",f[n+1][n+1]),x=y=n+1;
	while(x>1||y>1){
		int px=pre[x][y][0],py=pre[x][y][1];
		if(px==py){
			if(x==px+2&&y==py+2) ans.pb(mp(px,px+1));
			if(x==px+1&&y==py+3) ans.pb(mp(px,px+2));
			if(x==px&&y==py+3) ans.pb(mp(px+1,px+2));
		}else{
			if(x==py+1&&y==py+1) ans.pb(mp(px,py));
			if(x==py&&y==py+2) ans.pb(mp(px,py+1));
			if(x==px&&y==py+2) ans.pb(mp(py,py+1));
		}
		x=px;
		y=py;
	}
	reverse(ans.begin(),ans.end());
	for(int i=0;i<ans.size();++i){
//		printf("%d %d\n",ans[i].fi,ans[i].se);
		if(ans[i].fi<=n) printf("%d ",ans[i].fi);
		if(ans[i].se<=n) printf("%d ",ans[i].se);
		printf("\n");
	}
	return 0;
}
/*
給定一個序列,每次可以刪除前3箇中的2個,代價為max(ai),剩餘一個時代價為a,求最小代價 

剩下的元素是一個單點 & 一個字尾

f[i,j]:單點在i,字尾左端點為j,最小時間為多少

f[i,i] -> f[i+2,i+2],f[i+1,i+3],f[i,i+3]
f[i,j] -> f[i,j+2],f[j+1,j+1],f[j,j+2]
*/