想哭啊,这道题写和调一共用了两个多小时,最后才发现死在了一个括号匹配上面,WA的一下就哭出来了,这个故事告诉我们查错的时候一定要检查括号匹配啊,有些是编译器看不出来的,现在心情还久久不能平静
首先进行分析
很容易写出一个dp转移方程
dp[i]=min(dp[j]+(i-j-1+cnt[i]-cnt[j]-L)^2);
注意到可以把括号里的
拆分成
用完全平方公式可以得到
dp[i]=min(dp[j]+(i-1+cnt[i]-L)^2+2*(i-1+cnt[i]-L) *(-j-cnt[j])+(j+cnt[j])^2)
扔掉(i-1+cnt[i]-L)^2
得到
dp[i]=dp[j]+(j+cnt[j])^2-2*(i-1+cnt[i]-L)*(j+cnt[j])
其中x和y均满足单调性,所以维护点集(x,y)就行了,维护凸包即可
用斜率优化做就行了
斜率优化讲解:
http://blog.csdn.net/NOIAu/article/details/71774994
#include
#include
#define MAXN 500000+10
using namespace std;
int q[MAXN];
int head,tail;
int N,L;
long long temp;
long long cnt[MAXN],dp[MAXN];
long long getx(int i){ return i+cnt[i]; }
long long gety(int i){ return dp[i]+(i+cnt[i])*(i+cnt[i]); }
int main(){
scanf("%d%d",&N,&L); q[tail]=0;
for(int i=1;i<=N;i++) scanf("%lld",cnt+i),cnt[i]+=cnt[i-1];
for(int i=1;i<=N;i++){
long long k=2*(i-1-L+cnt[i]);
while(headq[head+1])-k*getx(q[head+1])<=gety(q[head])-k*getx(q[head])) ++head;
dp[i]=gety(q[head])-k*getx(q[head])+k*k/4;
while(headq[tail-1]))*(getx(i)-getx(q[tail]))>=(gety(i)-gety(q[tail]))*(getx(i)-getx(q[tail-1]))) --tail;
q[++tail]=i;
}
printf("%lld\n",dp[N]);
return 0;
}
不要问我为什么这次没用vj测题
我交了几次,最开始交的已经pending了1h了
多半是评测机睡着了
P.S:本来我的代码多简洁的,设了getx()函数,gety()函数,getb()函数,getk()函数,很多东西可以缩的,然而我已经调到不相信人生了,全部都老老实实改成了现在这个样子