[BalticOI 2009 Day1]甲虫
[BalticOI 2009]甲虫
Solution
比较套路的区间dp,先按坐标排序,再找出零点所在位置,记为
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 307
#define ll long long
ll dp[N][N][2],t[N][N][2],a[N];
int n,m;
int main(){
freopen("data.in","r",stdin);
freopen("user.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
sort(a+1,a+1+n+1);
int pos;
for(int i=1;i<=n+1;i++)
if(!a[i]){pos=i;break;}
memset(dp,-63,sizeof(dp));
dp[pos][pos][0]=dp[pos][pos][1]=0;
t[pos][pos][0]=t[pos][pos][1]=m;
ll ans=0;
for(int l=2;l<=n+1;l++)
for(int i=1,j=i+l-1;j<=n+1;i++,j++){
if(dp[i+1][j][0]+t[i+1][j][0]-(a[i+1]-a[i])>dp[i][j][0]){
dp[i][j][0]=dp[i+1][j][0]+t[i+1][j][0]-(a[i+1]-a[i]);
t[i][j][0]=t[i+1][j][0]-(a[i+1]-a[i]);
}
if(dp[i+1][j][1]+t[i+1][j][1]-(a[j]-a[i])>dp[i][j][0]){
dp[i][j][0]=dp[i+1][j][1]+t[i+1][j][1]-(a[j]-a[i]);
t[i][j][0]=t[i+1][j][1]-(a[j]-a[i]);
}
if(dp[i][j-1][1]+t[i][j-1][1]-(a[j]-a[j-1])>dp[i][j][1]){
dp[i][j][1]=dp[i][j-1][1]+t[i][j-1][1]-(a[j]-a[j-1]);
t[i][j][1]=t[i][j-1][1]-(a[j]-a[j-1]);
}
if(dp[i][j-1][0]+t[i][j-1][0]-(a[j]-a[i])>dp[i][j][1]){
dp[i][j][1]=dp[i][j-1][0]+t[i][j-1][0]-(a[j]-a[i]);
t[i][j][1]=t[i][j-1][0]-(a[j]-a[i]);
}
ans=max(ans,max(dp[i][j][0],dp[i][j][1]));
}
printf("%lld",ans);
}
/*
3 15
6 -3 1
*/
然后你就可以得到
上述做法的问题在于虽然
那么总的答案就是
复杂度
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 307
#define ll long long
int n,m,pos=0;
ll dp[N][N][2],a[N];
inline ll calc(int lim){
memset(dp,127,sizeof(dp));
dp[pos][pos][0]=dp[pos][pos][1]=0;
for(int l=2;l<=lim;l++)
for(int i=1,j=i+l-1;j<=n;i++,j++){
dp[i][j][0]=min(dp[i][j][0],min(dp[i+1][j][0]+(a[i+1]-a[i])*(lim-l+1),dp[i+1][j][1]+(a[j]-a[i])*(lim-l+1)));
dp[i][j][1]=min(dp[i][j][1],min(dp[i][j-1][1]+(a[j]-a[j-1])*(lim-l+1),dp[i][j-1][0]+(a[j]-a[i])*(lim-l+1)));
}
ll ret=(1LL<<60);
for(int i=1,j=i+lim-1;j<=n;i++,j++)
ret=min(ret,min(dp[i][j][0],dp[i][j][1]));
// printf("%lld\n",ret);
return ret;
}
int main(){
// freopen("beetle.in","r",stdin);
// freopen("beetle.out","w",stdout);
scanf("%d%d",&n,&m);
bool tag=0;
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]),tag|=(!a[i]);
if(!tag) n++;
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
if(!a[i]){pos=i;break;}
ll ans=-1;
for(int i=1;i<=n;i++)
ans=max(ans,i*m-calc(i)-(!tag? m:0));
printf("%lld",ans);
}
/*
3 15
6 -3 1
*/
Tips
原来的所有坐标中可能有