Problem 1911. -- [Apio2010]特别行动队
题目意思:给定一组数,要求给起分组,每一组分后的值为该组的和x,带入f[x]=a*x^2+b*x+c取得f值,要求每一组的f值之和最大
思路:
肯定是动态规划的,但是按照最原始的方程肯定超时 n为1000000
O(n*n)伤不起,所以想到用斜率优化
设:x1,x2为 x的决策 x1<x2
那么:
F[x]=f[x1]+a*(sum[x]-sum[x1])^2+b*(sum[x]-sum[x1])+c 式子1 F[x]=f[x1]+a*(sum[x]-sum[x2])^2+b*(sum[x]-sum[x2])+c 式子2
式子1-式子2,得:
[f[x1]+a*sum[x1]*sum[x1]-b*sum[x1]-(f[x2]+a*sum[x2]*sum[x2]-b*sum[x2])]/(sum[x1]-sum[x2])>a*sum[x];
所以就可以看成:dy/dx>=a*sum[x]满足斜率式子
维护一个递减的的斜率即可。。
1 ************************************************************** 2 Problem: 1911 3 User: yzcstc 4 Language: C++ 5 Result: Accepted 6 Time:1252 ms 7 Memory:32840 kb 8 ************************************************************** 9 #include <iostream> 10 #include <cstring> 11 #include <string> 12 #include <cstdlib> 13 #include <algorithm> 14 #include <cstdio> 15 using namespace std; 16 const int maxn=1010101; 17 int n; 18 long long arr[maxn],f[maxn],sum[maxn],q[maxn],a,b,c; 19 20 void init(){ 21 scanf("%d",&n); 22 scanf("%lld%lld%lld",&a,&b,&c); 23 for (int i=1; i<=n; ++i ){ 24 scanf("%lld",&arr[i]); 25 sum[i]=sum[i-1]+arr[i]; 26 } 27 } 28 long long dy(int k1, int k2){ 29 return f[k1] + a*sum[k1]*sum[k1] - b*sum[k1] 30 -(f[k2] +a*sum[k2]* sum[k2] - b*sum[k2]); 31 } 32 33 long long dx(int k1, int k2){ 34 return sum[k1] - sum[k2]; 35 } 36 37 void solve(){ 38 int h = 1, t = 1, j; 39 long long tmp; 40 q[h] = 0; 41 for (int i = 1; i <= n; ++i){ 42 while (h<t&&dy(q[h],q[h+1])<=a*sum[i]*2*dx(q[h],q[h+1])) ++h; 43 j=q[h]; 44 tmp = sum[i]- sum[j]; 45 f[i]=f[j]+a*tmp*tmp+b*tmp+c; 46 while (h<t){ 47 if (dy(q[t],i)*dx(q[t-1],i)>=dy(q[t-1],i)*dx(q[t],i)) --t; 48 else break; 49 } 50 q[++t] = i; 51 } 52 printf("%lld\n",f[n]); 53 } 54 55 int main(){ 56 init(); 57 solve(); 58 } 59 ?
浙公网安备 33010602011771号