[POI2009]Kon
Description
火车沿途有N个车站,告诉你从每一站到每一站的人数,现在查票员只能查K次票,每次查票可以控制目前在车上的所有乘客的车票。求一个查票方案,使得控制的不同的乘客尽量多。 (显然对同一个乘客查票多次是没有意义的,只算一次)
Input
第一行正整数 N K (1≤K<N≤600, K≤50). 接下来N-1行,第i行第j个数描述第i站上,到第i+j站下的乘客个数。总乘客数≤2*10^9
Output
单调增的K个整数,用空格隔开,表示经过哪些站以后查票。
Sample Input
7 2
2 1 8 2 1 0
3 5 1 0 1
3 1 2 2
3 5 6
3 2
1
Sample Output
2 5
本题dp题,设f[i][k]表示到第i个车站检票k次所控制的人数,因为每次检票到下一次检票相当于检查了一个矩阵内的人数,所以可以据此转移。
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
int x=0,f=1;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline void print(int x){
if (x>=10) print(x/10);
putchar(x%10+'0');
}
const int N=6e2,M=50;
int A[N+10][N+10],sum[N+10][N+10],f[N+10][M+10],pre[N+10][M+10],stack[M+10];
int main(){
int n=read(),K=read(),Ans=-inf,ID=0;
for (int i=1;i<n;i++) for (int j=i+1;j<=n;j++) A[i][j]=read();
for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+A[i][j];
memset(f,128,sizeof(f));
f[0][0]=0;
for (int i=1;i<=n;i++){
for (int k=1;k<=K;k++){
for (int l=0;l<i;l++){
int tmp=sum[i][n]-sum[i][i]-sum[l][n]+sum[l][i];
if (f[i][k]<f[l][k-1]+tmp){
f[i][k]=f[l][k-1]+tmp;
pre[i][k]=l;
}
if (k==K&&Ans<f[i][k]){
Ans=f[i][k];
ID=i;
}
}
}
}
for (int i=ID,k=K;i;i=pre[i][k--]) stack[k]=i;
for (int i=1;i<=K;i++) printf("%d",stack[i]),i!=K?putchar(' '):putchar('\n');
return 0;
}