看起来很水,然而不会DP的蒟蒻并不会做,PoPoqqq orz
设$f[i][j]$表示当前在第$i$个点和第$i+1$个点之间查票,已经查了$j$次的最大收益。然后就是那种很常见的枚举前一个结尾的转移,主要是贡献的求法,从$x$到$y$的贡献是$val[(x+1,y+1)][(y,n)]$(二维前缀和一下)。对于方案就在更新时记录上一个结尾即可

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=605,K=60; 6 int fsum[N][N],dp[N][K],las[N][K],outp[K]; 7 int n,k,ans,cnt,pos; 8 int main () 9 { 10 scanf("%d%d",&n,&k); 11 for(int i=1;i<n;i++) 12 for(int j=i+1;j<=n;j++) 13 scanf("%d",&fsum[i][j]); 14 for(int i=1;i<=n;i++) 15 for(int j=1;j<=n;j++) 16 fsum[i][j]+=fsum[i-1][j]+fsum[i][j-1]-fsum[i-1][j-1]; 17 memset(dp,0xcf,sizeof dp),dp[0][0]=0; 18 for(int i=1;i<n;i++) 19 for(int j=1;j<=k;j++) 20 for(int h=0;h<i;h++) 21 { 22 int tmp=fsum[i][n]-fsum[h][n]-fsum[i][i]+fsum[h][i]; 23 if(dp[h][j-1]+tmp>dp[i][j]) {dp[i][j]=dp[h][j-1]+tmp; las[i][j]=h;} 24 } 25 for(int i=1;i<n;i++) 26 if(dp[i][k]>ans) ans=dp[i][k],pos=i; 27 while(k) outp[++cnt]=pos,pos=las[pos][k--]; 28 sort(outp+1,outp+1+cnt); 29 for(int i=1;i<=cnt;i++) 30 printf("%d ",outp[i]); 31 return 0; 32 }