nssl1322,jzoj(初中)2109-清兵线【dp】

正题


题目大意

n n n个士兵在不同的位置,自己每秒可以往左移或者往右移动1格,并且干掉改格所在的士兵。
m m m秒,第 k k k秒干掉士兵可以获得 m − k m-k mk的价值,求最大价值之和。


解题思路

离散化先
然后我们干掉的士兵一定一个线段,所以我们设
f i , j , t , 0 / 1 f_{i,j,t,0/1} fi,j,t,0/1表示第 t   s t\ s t s已经干掉了 i ∼ j i\sim j ij的士兵,然后在最左边还是在最右边

但是我们发现 t t t的范围十分的大,我们考虑转换。

假设我们总共要干掉 k k k个人,如果还剩下 z z z个人没被干掉,那么没移动一步就会消耗 k k k点价值。

那么我们就可以列出新的方程 f i , j , k , 0 / 1 f_{i,j,k,0/1} fi,j,k,0/1表示总共要干掉 i ∼ j i\sim j ij的士兵,然后在最左边还是在最右边。

然后因为全程 k k k那个维度不会有任何交接我们可以不用记录,但是还是要枚举 k k k

最终状态:
f i , j , 0 / 1 f_{i,j,0/1} fi,j,0/1表示总共干掉 k k k个人,已经干掉了 i ∼ j i\sim j ij的人,在最左边还是在最右边,

那么我们可以列出动态转移方程
f i , j , 0 = m a x { f i + 1 , j , 0 + m − d i s t ( i , i + 1 ) ∗ ( k − j + i ) , f i + 1 , j , 1 + m − d i s t ( i , j ) ∗ ( k − j + i ) } f_{i,j,0}=max\{f_{i+1,j,0}+m-dist(i,i+1)*(k-j+i),f_{i+1,j,1}+m-dist(i,j)*(k-j+i)\} fi,j,0=max{fi+1,j,0+mdist(i,i+1)(kj+i),fi+1,j,1+mdist(i,j)(kj+i)}
f i , j , 1 = m a x { f i , j − 1 , 1 + m − d i s t ( j , j − 1 ) ∗ ( k − j + i ) , f i , j − 1 , 0 + m − d i s t ( i , j ) ∗ ( k − j + i ) } f_{i,j,1}=max\{f_{i,j-1,1}+m-dist(j,j-1)*(k-j+i),f_{i,j-1,0}+m-dist(i,j)*(k-j+i)\} fi,j,1=max{fi,j1,1+mdist(j,j1)(kj+i),fi,j1,0+mdist(i,j)(kj+i)}

然后答案就是 f l , r ( r − l + 1 = k , m i d ∈ [ l . . r ] ) f_{l,r}(r-l+1=k,mid\in [l..r]) fl,r(rl+1=k,mid[l..r])


c o d e code code

#pragma GCC optimize(2)
#include
#include
#include
#include 
using namespace std;
const int N=320;
int n,m,a[N],ans,K;
int f[N][N][2];
inline int read() {
	int x=0,f=1; char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
	while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
	return x*f;
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=n;i++)
	  a[i]=read();
	a[++n]=0;
	sort(a+1,a+1+n);
	int mid=lower_bound(a+1,a+1+n,0)-a;
	for(K=1;K<=n;K++){
		memset(f,0xcf,sizeof(f));
		f[mid][mid][0]=f[mid][mid][1]=0;
		for(int i=mid;i>0;i--)
		  for(int j=mid;j<=n;j++){
			if(i==j) continue; 
		  	if(j-i+1>K) break;
		  	f[i][j][0]=max(f[i+1][j][0]+m-(a[i+1]-a[i])*(K-j+i),f[i+1][j][1]+m-(a[j]-a[i])*(K-j+i));
		  	f[i][j][1]=max(f[i][j-1][1]+m-(a[j]-a[j-1])*(K-j+i),f[i][j-1][0]+m-(a[j]-a[i])*(K-j+i));
		  	if(j-i+1==K) 
			  ans=max(ans,max(f[i][j][0],f[i][j][1]));
		  } 
	}
	printf("%d",ans); 
}

你可能感兴趣的:(dp)