解题:POI 2009 Ticket Inspector

题面

看起来很水,然而不会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 }
View Code
原文地址:https://www.cnblogs.com/ydnhaha/p/9755763.html