[TIOJ] 1997. 數列切割

題目連結:http://tioj.infor.org/problems/1997
校內複賽的時候只喇到$k \leq 3$的測資,不過感覺這題是DP,只是賽中一直想不太出來,後來被雷了才知道這題的做法...
狀態設成$dp[i][j]$代表用前$i$個湊出$j$組的最大值可能為多少,而很明顯知道若是現在再加一個數,可以選擇的就是變成$dp[i+1][j+1]$或$dp[i+1][j]$,所以就照著這DP下去就好了,然後記得判一下奇偶之類的。
#include <bits/stdc++.h>
using namespace std;
typedef long long lld;
typedef pair<int,int> PII;
#define FF first
#define SS second
const int N = 1000000 + 5;
const lld INF = 1LL<<40;

int arr[N];
lld dp[N][7];
PII ori[N][7];

int main(){
	ios_base::sync_with_stdio(0);cin.tie(0);
	int n, k; cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>arr[i];
	fill(dp[1], dp[n]+7, -INF);
	dp[1][1]=arr[1];
	for(int j=1;j<=k;j++){
		for(int i=j;i<n;i++){
			if(j&1){
				if(dp[i][j]+arr[i+1] > dp[i+1][j]){
					dp[i+1][j] = dp[i][j]+arr[i+1];
					ori[i+1][j] = {i, j};
				}
				if(i >= j and dp[i][j]-arr[i+1] > dp[i+1][j+1]){
					dp[i+1][j+1] = dp[i][j]-arr[i+1];
					ori[i+1][j+1] = {i, j};
				}
			}else{
				if(dp[i][j]-arr[i+1] > dp[i+1][j]){
					dp[i+1][j] = dp[i][j]-arr[i+1];
					ori[i+1][j] = {i, j};
				}
				if(i >= j and dp[i][j]+arr[i+1] > dp[i+1][j+1]){
					dp[i+1][j+1] = dp[i][j]+arr[i+1];
					ori[i+1][j+1] = {i, j};
				}
			}
		}
	}
	while(n!=0 and k!=0){
		int nn = ori[n][k].FF, kk = ori[n][k].SS;
		if(k!=kk and nn!=0) cout<<nn<<'\n';
		n=nn, k=kk;
	}
	return 0;
}

留言

這個網誌中的熱門文章

[NPSC] 2009初賽 E. 檸檬汽水傳說

[TIOJ] 1902. 「殿仁.王,不認識,誰啊?」,然後他就死了……

[AtCoder] [經典競程 90 題] 024 - Select +/- One(★2)