DP/斜率优化
根据题目描述很容易列出动规方程:$$ f[i]=min\{ f[j]+(s[i]-s[j]+i-j-1-L)^2 \}$$
其中 $$s[i]=\sum_{k=1}^{i} c[k] $$
而$x$即为$s[i]-s[j]+i-j-1$
这个$x$的表示实在太不好看,我们容易发现$i-j$其实是可以跟$s[i]-s[j]$合到一起的,即令 $c[i]=c[i]+1$,则$s[i]=\sum_{k=1}^{i} (c[i]+1)=\sum_{k=1}^{i}c[i]+i $,所以$x=s[i]-s[j]-1$。再将那个$-1$与$L$合并,即$L=L+1$,然后我们就得到整理后的方程:$$ f[i]=min\{ f[j]+(s[i]-s[j]-L)^2 \} $$
证明决策单调性:$( j > k )$
\[ \begin{aligned} f[j]+(s[i]-s[j]-L)^2 &< f[k]+(s[i]-s[k]-L)^2 \\ f[j]-f[k]+(s[j]^2-s[k]^2) &< 2*(s[i]-L)*(s[j]-s[k]) \\ \frac{ f[j]-f[k]+(s[j]^2-s[k]^2) }{ 2*(s[j]-s[k]) } &< s[i]-L \end{aligned} \]
这里将 $s[i]-L$ 当作一个整体来计算
1 /************************************************************** 2 Problem: 1010 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:132 ms 7 Memory:2640 kb 8 ****************************************************************/ 9 10 //BZOJ 1010 11 #include<cmath> 12 #include<vector> 13 #include<cstdio> 14 #include<cstring> 15 #include<cstdlib> 16 #include<iostream> 17 #include<algorithm> 18 #define rep(i,n) for(int i=0;i<n;++i) 19 #define F(i,j,n) for(int i=j;i<=n;++i) 20 #define D(i,j,n) for(int i=j;i>=n;--i) 21 #define pb push_back 22 using namespace std; 23 int getint(){ 24 int v=0,sign=1; char ch=getchar(); 25 while(ch<‘0‘||ch>‘9‘){ if (ch==‘-‘) sign=-1; ch=getchar();} 26 while(ch>=‘0‘&&ch<=‘9‘){ v=v*10+ch-‘0‘; ch=getchar();} 27 return v*=sign; 28 } 29 const int N=50010; 30 typedef long long LL; 31 /******************tamplate*********************/ 32 LL c[N],s[N],f[N]; 33 int q[N],l,r; 34 double slop(int k,int j){ 35 return double(f[j]+s[j]*s[j]-f[k]-s[k]*s[k])/ 36 double(2*(s[j]-s[k])); 37 } 38 int main(){ 39 int n=getint(),L=getint()+1; 40 F(i,1,n){ 41 c[i]=getint()+1; 42 s[i]=s[i-1]+c[i]; 43 } 44 F(i,1,n){ 45 while(l<r && slop(q[l],q[l+1])<s[i]-L) l++; 46 int t=q[l]; 47 f[i]=f[t]+(s[i]-s[t]-L)*(s[i]-s[t]-L); 48 while(l<r && slop(q[r-1],q[r])>slop(q[r],i))r--; 49 q[++r]=i; 50 } 51 printf("%lld\n",f[n]); 52 return 0; 53 }
时间: 2024-10-11 01:26:24