HDU - 3507 Print Article (斜率DP优化)
1 #include <iostream> 2 #include <queue> 3 #include <stack> 4 #include <cstdio> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <bitset> 9 #include <algorithm> 10 #include <cmath> 11 #include <cstring> 12 #include <cstdlib> 13 #include <string> 14 #include <sstream> 15 #include <time.h> 16 #define x first 17 #define y second 18 #define pb push_back 19 #define mp make_pair 20 #define lson l,m,rt*2 21 #define rson m+1,r,rt*2+1 22 #define mt(A,B) memset(A,B,sizeof(A)) 23 #define lowbit(x) (x&(-x)) 24 using namespace std; 25 typedef long long LL; 26 //const double PI = acos(-1); 27 const int N=5e5+10; 28 const LL mod=1e9+7; 29 const int inf = 0x3f3f3f3f; 30 const LL INF=0x3f3f3f3f3f3f3f3fLL; 31 const double esp=1e-10; 32 int n,q[N]; 33 LL m,sum[N],dp[N]; 34 //dp的斜率优化就是把那些没用的点舍弃,降低尝试次数从而提高效率。 35 //如果up(j,k)/down(j,k)<=sum[i],则说明位置j比位置k更优,则位置k可以直接舍弃。 36 //维护一个下凸折线,用单调队列维护,类似凸包的维护。 37 LL up(int j,int k)//斜率优化时的分子 38 { 39 return dp[j]+sum[j]*sum[j]-dp[k]-sum[k]*sum[k]; 40 } 41 LL down(int j,int k)//斜率优化时的分母 42 { 43 return 2*sum[j]-2*sum[k]; 44 } 45 int main() 46 { 47 #ifdef Local 48 freopen("data.txt","r",stdin); 49 #endif 50 ios::sync_with_stdio(false); 51 cin.tie(0); 52 while(cin>>n>>m) 53 { 54 int head=0,tail=0; 55 sum[0]=0;dp[0]=0; 56 for(int i=1;i<=n;i++) 57 { 58 cin>>sum[i]; 59 sum[i]+=sum[i-1]; 60 } 61 q[tail++]=0; 62 for(int i=1;i<=n;i++) 63 { 64 //从head开始寻找,如果满足up(q[head+1],q[head])/down(q[head+1],q[head])<=sum[i]则说明q[head+1]的点优于q[head]点,直接跳过 65 while(head+1<tail&&up(q[head+1],q[head])<=sum[i]*down(q[head+1],q[head]))head++; 66 dp[i]=dp[q[head]]+(sum[i]-sum[q[head]])*((sum[i]-sum[q[head]]))+m; 67 //新加入的i点可能与原来单调队列中的点形成上凸折线,所以需要把那些形成上凸折线的点剔除掉。 68 //即如果k(i,q[tail-1])<k(q[tail-1],q[tail-2]),则形成上凸折线,q[tail-1]该点必须剔除。 69 //最后再把i点加入单调队列。 70 while(head+1<tail&&up(q[tail-1],q[tail-2])*down(i,q[tail-1])>=down(q[tail-1],q[tail-2])*up(i,q[tail-1]))tail--; 71 q[tail++]=i; 72 } 73 cout<<dp[n]<<endl; 74 } 75 return 0; 76 #ifdef Local 77 cerr << "time: " << (LL) clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl; 78 #endif 79 }