BZOJ1911 [Apio2010]特别行动队
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!
Description
Input
Output
Sample Input
4
-1 10 -20
2 2 3 4
-1 10 -20
2 2 3 4
Sample Output
9
HINT
正解:DP+斜率优化
解题报告:
朴素DP很好想,就是$${f[i]=max(f[j]+a*(s[i]-s[j])^2+b*(s[i]-s[j])+c) (j<i)}$$
但是只有50分,考虑优化。
因为这个式子一看就很可推,试着证明有没有单调性或者可以弄出斜率...
如果j>k,且j比k更优,当且仅当
$${f[j]-f[k]+a*sum[j]^2-a*sum[k]^2+b*(sum[k]-sum[j])>2*a*(sum[j]-sum[k])*sum[i]}$$
移过去就是$${\frac {f[j]-f[k]+a*sum[j]^2-a*sum[k]^2+b*(sum[k]-sum[j])}{2*a*(sum[j]-sum[k])} < sum[i] }$$
(ps:带a的那个式子,就是分母,是小于0的,所以要变号...)
然后维护一个斜率单增的单调队列,相当于是一个下凸的凸包,就ok了。
1 //It is made by ljh2000 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 using namespace std; 14 typedef long long LL; 15 const int inf = (1<<30); 16 const int MAXN = 1000011; 17 int n; 18 LL a,b,c; 19 LL s[MAXN],f[MAXN]; 20 int dui[MAXN],head,tail; 21 22 inline int getint() 23 { 24 int w=0,q=0; char c=getchar(); 25 while((c<'0' || c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); 26 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w; 27 } 28 inline LL count(int x,int y){ return ( (f[x]-f[y])+a*(s[x]*s[x]-s[y]*s[y])-b*(s[x]-s[y]) )/(a*2*(s[x]-s[y])); } 29 inline void work(){ 30 n=getint(); a=getint(); b=getint(); c=getint(); int x; 31 for(int i=1;i<=n;i++) x=getint(),s[i]=s[i-1]+x; 32 head=tail=1; dui[tail]=0; int from; 33 for(int i=1;i<=n;i++) { 34 while(head<tail && count(dui[head+1],dui[head])<s[i]) head++; 35 from=dui[head]; f[i]=f[from]+a*(s[i]-s[from])*(s[i]-s[from])+b*(s[i]-s[from])+c; 36 while(head<tail && count(dui[tail-1],dui[tail])>count(dui[tail],i)) tail--; 37 dui[++tail]=i; 38 } 39 printf("%lld",f[n]); 40 } 41 42 int main() 43 { 44 work(); 45 return 0; 46 }
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!