P3486 [POI 2009] KON-Ticket Inspector

P3486 [POI 2009] KON-Ticket Inspector

题目描述

\(n\) 个车站,现在有一辆火车从 \(1\)\(n\) 驶过,给出 \(a_{i,j}\) 代表从 \(i\) 站上车 \(j\) 站下车的人的个数。列车行驶过程中你有 \(K\) 次检票机会,所有当前在车上的人会被检票,问最多能检多少个不同的人的票。

输入格式

第一行正整数 \(N,K\)\(1≤K<N≤600\)\(K≤50\)。接下来 \(N-1\) 行,第 \(i\) 行第 \(j\) 个数描述第 \(i\) 站上,到第 \(i+j\) 站下的乘客个数。总乘客数 \(≤2\times 10^9\)

输出格式

单调增的 \(K\) 个整数,用空格隔开,表示经过哪些站以后查票。

输入输出样例 #1

输入 #1

7 2
2 1 8 2 1 0
3 5 1 0 1
3 1 2 2
3 5 6
3 2
1

输出 #1

2 5

思路

看了数据范围之后,\(0\) 秒想到dp,这道题可以一眼出状态:

\(f_{i,j}\) 指前 \(i\) 站检票 \(j\) 次的最多检票人数

那么转移方程一眼

\[f_{i,j}=\max\{f_{k,j-1}+val(k+1,i),f_{i-1,j}\} \]

然后处理 \(val(k+1,i)\) 直接手玩样例之后就可以发现这玩意就是个二维前缀和

最后注意输出的是方案而不是最后的最多人数

code

#include <bits/stdc++.h>
using namespace std;
const int N=700,M=100;
int f[M][N];
int a[N][N],n,k,sum[N][N];
int pre[M][N],tot,sta[N];
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n>>k;
	for(int i=1;i<n;i++){
		for(int j=1;i+j<=n;j++){
			cin>>a[i][i+j];
		}
	}
	for(int i=1;i<n;i++){
		for(int j=1;j<=n;j++){
			sum[i][j]+=sum[i][j-1];
			sum[i][j]+=sum[i-1][j];
			sum[i][j]+=a[i][j];
			sum[i][j]-=sum[i-1][j-1];
		}
	}
	for(int i=1;i<=k;i++){
		for(int j=i;j<n;j++){
			for(int p=i-1;p<j;p++){
				int tmp=f[i-1][p]+sum[j][n]-sum[j][j]-sum[p][n]+sum[p][j];
				if(f[i][j]<tmp){
					pre[i][j]=p;
					f[i][j]=tmp;
				}
			}
		}
	}
	int lst=0,tmp=k-1,ans=0;
	for(int i=k;i<n;i++){
		if(f[k][i]>ans){
			ans=f[k][i];
			lst=i;
		}
	} 
	sta[++tot]=lst;
	while(lst){
		lst=pre[k-tot+1][lst];
		sta[++tot]=lst;
	}
	for(int i=tot-1;i>=1;i--){
		cout<<sta[i]<<' ';
	}
	return 0;
}
posted @ 2025-07-29 16:28  shencheng4014  阅读(15)  评论(0)    收藏  举报