3156: 防御准备
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 951 Solved: 446
[Submit][Status][Discuss]
Description
Input
第一行为一个整数N表示战线的总长度。
第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai。
Output
共一个整数,表示最小的战线花费值。
Sample Input
10
2 3 1 5 4 5 6 3 1 2
2 3 1 5 4 5 6 3 1 2
Sample Output
18
HINT
1<=N<=10^6,1<=Ai<=10^9
Source
Solution
斜率优化DP
方案由后面的转移? 翻转序列即可..
然后就是转移方程 $dp[i]=min(dp[i],dp[j]+sum[i-1]-sum[j]-(i-j-1)*j+A[i]$
然后斜率优化一下,比较的裸,然后即可
值得注意的地方:
转移的时候,$i=1$提前的处理出来..
在计算答案的时候,注意加long long否则会WA成狗..
Code
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; int read() { int x=0,f=1; char ch=getchar(); while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } #define maxn 1000100 int n,A[maxn]; int que[maxn],l,r; long long dp[maxn],sumid[maxn],ans; double slope(long long i,long long j) {return (double)(dp[i]-dp[j]-sumid[i]+sumid[j]+i-j+i*i-j*j)/(double)(i-j);} int main() { n=read(); ans=(long long)1<<60; for (int i=n; i>=1; i--) A[i]=read(); for (int i=1; i<=n; i++) sumid[i]=sumid[i-1]+i; dp[1]=A[1]; que[1]=1; l=r=1; for (int tmp,i=2; i<=n; i++) { while (l<r && slope(que[l],que[l+1])<i) l++; tmp=que[l]; dp[i]=dp[tmp]+sumid[i-1]-sumid[tmp]-(i-tmp-1)*tmp+A[i]; while (l<r && slope(que[r],i)<slope(que[r-1],que[r])) r--; que[++r]=i; } for (int i=1; i<=n; i++) ans=min(ans,dp[i]+sumid[n]-sumid[i]-(long long)(n-i)*i); printf("%lld ",ans); return 0; }
上文所述WA成狗...MDZZ