【BZOJ】【3156】防御准备
DP/斜率优化
斜率优化的裸题……
sigh……又把$10^6$当成10W了……RE了N发
这题还是很水的
当然逆序也能做……不过还是整个反过来比较顺手
反转后的a[0]=反转前的a[n],以此类推直到a[n-1],反转后的a[n]=0;
令f[0]=a[0],因为最初状态必须选第一个守卫塔。
然后定义f[i]表示在第 i 个位置放守卫塔,0~i 的代价最小值
易得$f[i]=min\{ f[j]+\frac{(i-j)*(i-j-1)}{2}+a[i] \} $
单调性证明:$( j > k ) $
\[ \begin{aligned} f[j]-f[k]+\frac{(i-j)*(i-j-1)}{2}-\frac{ (i-k)*(i-k-1)}{2} &< 0 \\ f[j]-f[k]+\frac{j^2+j-k^2-k}{2} &< i*(j-k) \\ \frac{f[j]-f[k]+\frac{j^2+j-k^2-k}{2}}{j-k} &< i \end{aligned} \]
1 /************************************************************** 2 Problem: 3156 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:2476 ms 7 Memory:24708 kb 8 ****************************************************************/ 9 10 //BZOJ 3156 11 #include<cstdio> 12 #include<iostream> 13 #include<algorithm> 14 #define rep(i,n) for(int i=0;i<n;++i) 15 #define F(i,j,n) for(int i=j;i<=n;++i) 16 #define D(i,j,n) for(int i=j;i>=n;--i) 17 #define pb push_back 18 using namespace std; 19 int getint(){ 20 int v=0,sign=1; char ch=getchar(); 21 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 22 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 23 return v*sign; 24 } 25 const int N=1000010; 26 typedef long long LL; 27 /******************tamplate*********************/ 28 LL n,q[N],l,r; 29 LL a[N],f[N]; 30 inline double slop(LL k,LL j){ 31 return double(f[j]-f[k]+(j*j+j-k*k-k)/2.0)/double(j-k); 32 } 33 int main(){ 34 n=getint(); 35 D(i,n-1,0) a[i]=getint(); 36 f[0]=a[0]; 37 F(i,1,n){ 38 while(l<r && slop(q[l],q[l+1])<i)l++; 39 int t=q[l]; 40 f[i]=f[t]+(LL)(i-t)*(i-t-1)/2+a[i]; 41 while(l<r && slop(q[r-1],q[r])>slop(q[r],i)) r--; 42 q[++r]=i; 43 } 44 printf("%lld\n",f[n]); 45 return 0; 46 }
3156: 防御准备
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 618 Solved: 296
[Submit][Status][Discuss]
Description
Input
第一行为一个整数N表示战线的总长度。
第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai。
Output
共一个整数,表示最小的战线花费值。
Sample Input
10
2 3 1 5 4 5 6 3 1 2
Sample Output
18
HINT
1<=N<=10^6,1<=Ai<=10^9