正题
题目大意
nnn个士兵在不同的位置,自己每秒可以往左移或者往右移动1格,并且干掉改格所在的士兵。
有mmm秒,第kkk秒干掉士兵可以获得m−km-km−k的价值,求最大价值之和。
解题思路
离散化先
然后我们干掉的士兵一定一个线段,所以我们设
fi,j,t,0/1f_{i,j,t,0/1}fi,j,t,0/1表示第tst\ st s已经干掉了i∼ji\sim ji∼j的士兵,然后在最左边还是在最右边
但是我们发现ttt的范围十分的大,我们考虑转换。
假设我们总共要干掉kkk个人,如果还剩下zzz个人没被干掉,那么没移动一步就会消耗kkk点价值。
那么我们就可以列出新的方程fi,j,k,0/1f_{i,j,k,0/1}fi,j,k,0/1表示总共要干掉i∼ji\sim ji∼j的士兵,然后在最左边还是在最右边。
然后因为全程kkk那个维度不会有任何交接我们可以不用记录,但是还是要枚举kkk。
最终状态:
设fi,j,0/1f_{i,j,0/1}fi,j,0/1表示总共干掉kkk个人,已经干掉了i∼ji\sim ji∼j的人,在最左边还是在最右边,
那么我们可以列出动态转移方程
fi,j,0=max{fi+1,j,0+m−dist(i,i+1)∗(k−j+i),fi+1,j,1+m−dist(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+m−dist(i,i+1)∗(k−j+i),fi+1,j,1+m−dist(i,j)∗(k−j+i)}
fi,j,1=max{fi,j−1,1+m−dist(j,j−1)∗(k−j+i),fi,j−1,0+m−dist(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,j−1,1+m−dist(j,j−1)∗(k−j+i),fi,j−1,0+m−dist(i,j)∗(k−j+i)}
然后答案就是fl,r(r−l+1=k,mid∈[l..r])f_{l,r}(r-l+1=k,mid\in [l..r])fl,r(r−l+1=k,mid∈[l..r])
codecodecode
#pragma GCC optimize(2)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cctype>
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);
}