【解题思路】

  设s[i]=i+∑c[j](j∈[1,n]∩N)

  易得转移方程f[i]=min{f[j]+(s[i]-s[j]-L-1)2},朴素算法复杂度O(n2)。

  考虑斜率优化:记T[i]=s[i]+L+1

若成立f[j]+(s[i]-s[j]-L-1)2<=f[k]+(s[i]-s[k]-L-1)2(j<k)

<=>f[j]+(s[i]-T[j])2<=f[k]+(s[i]-T[k])2

<=>(f[j]+T[j]2)-(f[k]+T[k]2)<=2*s[i]*(T[j]-T[k])

<=>((f[j]+T[j]2)-(f[k]+T[k]2))/(T[j]-T[k])<=2*s[i]

则设P[i](T[i],f[i]+T[i]2),维护单调队列(按相邻两点斜率降序排序),当队列要加入i时,P[j]和P[k]的共存条件是(P[j]-P[k])斜率不超过2*s[i],整个单调队列呈一个下凸壳。时间复杂度O(n)。

【参考代码】

 1 #include <cctype>
 2 #include <cstdio>
 3 #define REP(I,start,end) for(int I=(start);I<=(end);I++)
 4 #define PER(I,start,end) for(int I=(start);I>=(end);I--)
 5 typedef unsigned short US;
 6 typedef unsigned long UL;
 7 typedef long long LL;
 8 typedef unsigned long long ULL;
 9 typedef long double LD;
10 inline int space()
11 {
12     return putchar(' ');
13 }
14 inline int enter()
15 {
16     return putchar('\n');
17 }
18 inline bool eoln(char ptr)
19 {
20     return ptr=='\n';
21 }
22 inline bool eof(char ptr)
23 {
24     return ptr=='\0';
25 }
26 inline int getint()
27 {
28     char ch=getchar();
29     for(;!isdigit(ch)&&ch!='+'&&ch!='-';ch=getchar());
30     bool impositive=ch=='-';
31     if(impositive)
32         ch=getchar();
33     int result=0;
34     for(;isdigit(ch);ch=getchar())
35         result=(result<<3)+(result<<1)+ch-'0';
36     return impositive?-result:result;
37 }
38 template<typename integer> inline int write(integer n)
39 {
40     integer now=n;
41     bool impositive=now<0;
42     if(impositive)
43     {
44         putchar('-');
45         now=-now;
46     }
47     char sav[20];
48     sav[0]=now%10+'0';
49     int result=1;
50     for(;now/=10;sav[result++]=now%10+'0');
51     PER(i,result-1,0)
52         putchar(sav[i]);
53     return result+impositive;
54 }
55 template<typename integer> inline ULL sqr(integer n)
56 {
57     return ULL(n)*n;
58 }
59 //========================Header Template=====================
60 using namespace std;
61 int q[500010];
62 ULL dp[500010],sum[500010],L;
63 inline ULL getDP(int i,int j)
64 {
65     return dp[j]+sqr(sum[i]-sum[j]-L);
66 }
67 inline ULL getUP(int j,int k)
68 {
69     return dp[j]+sqr(sum[j]+L)-dp[k]-sqr(sum[k]+L);
70 }
71 inline ULL getDOWN(int j,int k)
72 {
73     return sum[j]-sum[k]<<1;
74 }
75 int main()
76 {
77     int n=getint();
78     L=getint()+1ull;
79     sum[0]=q[0]=dp[0]=0ull;
80     REP(i,1,n)
81         sum[i]=sum[i-1]+getint()+1ull;
82     int head=0,tail=1;
83     REP(i,1,n)
84     {
85         while(head+1<tail&&getUP(q[head+1],q[head])<=sum[i]*getDOWN(q[head+1],q[head]))
86             head++;
87         dp[i]=getDP(i,q[head]);
88         while(head+1<tail&&getUP(i,q[tail-1])*getDOWN(q[tail-1],q[tail-2])<getUP(q[tail-1],q[tail-2])*getDOWN(i,q[tail-1]))
89             tail--;
90         q[tail++]=i;
91     }
92     write(dp[n]);
93     enter();
94     return 0;
95 }
View Code