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;
}

浙公网安备 33010602011771号