[Jzoj] 3413.KC的瓷器

题目描述

K C KC KC 来到了一个盛产瓷器的国度。他来到了一位商人的店铺。在这个店铺中, K C KC KC 看到了一个有 N ( 1 < = N < = 100 ) N(1<=N<=100) N(1<=N<=100)排的柜子,每排都有一些瓷器,每排不超过 100 100 100 个。那些精美的艺术品使 K C KC KC 一下心动了,决定从 N N N 排的商品中买下 M ( 1 < = M < = 10000 ) M(1<=M<=10000) M(1<=M<=10000) 个瓷器。

这个商人看 K C KC KC 的脸上长满了痘子,就像苔藓一样,跟精美的瓷器相比相差太多,认为这么精致的艺术品被这样的人买走艺术价值会大打折扣。商人感到不爽,于是规定每次取商品只能取其中一排的最左边或者最右边那个,想为难 K C KC KC

现在 K C KC KC 又获知每个瓷器的价值(用一个不超过 100 100 100 的正整数表示),他希望取出的 M M M 个商品的总价值最大。

题目解析

先预处理 T a k e [ i ] [ j ] Take[i][j] Take[i][j] ,表示从第i排中取出j个瓷器的最大价值,以及 a [ i ] [ j ] a[i][j] a[i][j] 表示第 i i i 排前 j j j 个瓷器的总价值即前缀和。

考虑对于每一排取出最左边的 k k k 个,那么剩下的 j − k j-k jk 个就是最右边的, ( 1 < = k < = c ) (1<=k<=c) (1<=k<=c)
易得: T a k e [ i ] [ j ] = m a x ( a [ i ] [ k ] + a [ i ] [ c ] − a [ i ] [ c − j + k ] ) , c Take[i][j]=max(a[i][k]+a[i][c]-a[i][c-j+k]),c Take[i][j]=max(a[i][k]+a[i][c]a[i][cj+k]),c表示第 i i i 排的瓷器数目。

接下来 D P DP DP f [ i ] [ j ] f[i][j] f[i][j] 表示从前i排取出j个的最大价值。
那么 f [ i ] [ j ] = m a x ( f [ i ] [ j ] , f [ i − 1 ] [ j − k ] + T a k e [ i ] [ k ] ) f[i][j]=max(f[i][j],f[i-1][j-k]+Take[i][k]) f[i][j]=max(f[i][j],f[i1][jk]+Take[i][k])

代码

#include
#define N 105
using namespace std;
int n,m;
int a[N][N],f[N][N*N],sum[N][N];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
	  scanf("%d",&a[i][0]);
	  for(int j=1;j<=a[i][0];j++)
	   scanf("%d",&a[i][j]),sum[i][j]=sum[i][j-1]+a[i][j];
	}
	for(int i=1;i<=n;i++)
	{
	  for(int j=1;j<=m;j++) f[i][j]=f[i-1][j];
	  for(int j=1;j<=a[i][0];j++)
	  {
	  	int tmp=0;
	  	for(int k=0;k<=j;k++) tmp=max(tmp,sum[i][k]+sum[i][a[i][0]]-sum[i][a[i][0]-j+k]);
	  	for(int k=j;k<=m;k++) f[i][k]=max(f[i][k],f[i-1][k-j]+tmp);
	  }
	}
	cout<<f[n][m];
	return 0;
}

你可能感兴趣的:([Jzoj] 3413.KC的瓷器)