斜率DP小结

参考博客:https://blog.csdn.net/shiyongyang/article/details/78299894?readlog

        https://www.cnblogs.com/MashiroSky/p/6009685.html

1.BZOJ 1010

题意:有n个数,分成连续的若干段,每段(假设从第j个到第i个组成一段)的分数为 (X-L)^2,X为j-i+Sigma(Ck) i<=k<=j,其中L是一个常量。目标:各段分数的总和最小。

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstdio>
 6 #include<algorithm>
 7 #include<string>
 8 #include<map>
 9 #include<queue>
10 #include<vector>
11 #include<stack>
12 #define ll long long
13 #define maxn 4001000
14 #define lson l,m,rt<<1
15 #define rson m+1,r,rt<<1|1
16 #define rep(i,a,b) for(int i=a;i<=b;i++)
17 #define SWAP(x,y,t) ( (t)=(x),(x)=(y),(y)=(t) )
18 const int N=50100;
19 ll s[N],f[N],n,x,L,j,q[N],tail,head;
20 inline double X(ll i) {return s[i];}
21 inline double Y(ll i) {return f[i]+(s[i]+L)*(s[i]+L);}
22 inline double slope(ll i,ll j){return (Y(j)-Y(i))/(X(j)-X(i));}
23 using namespace std;
24 int main()
25 {
26     scanf("%lld%lld",&n,&L);L++,s[0]=0;head=tail=1;q[1]=0;    
27     rep(i,1,n) scanf("%lld",&s[i]),s[i]+=s[i-1];
28     rep(i,1,n) s[i]+=i;
29     rep(i,1,n)
30     {
31         while(head<tail && slope(q[head],q[head+1])<2*s[i]) head++;
32         j=q[head];f[i]=f[j]+(s[i]-s[j]-L)*(s[i]-s[j]-L);
33         while(head<tail&& slope(q[tail-1],q[tail])>slope(q[tail],i)) tail--;
34         q[++tail]=i;    
35     }
36     printf("%lld\n",f[n]);
37 } 
View Code

 

2.BZOJ 1096

题意:有N个工厂按编号顺序排成一条直线,第1个工厂到第i个工厂的距离为dis[i], 第i个工厂一开始堆积着p[i]个货物,现在要紧急把所有货物装进仓库里。在第i个工厂建仓库需要c[i]的代价,对于没有建立仓库的工厂,其货物应被运往其他的仓库进行储藏,且只能往编号大仓库的运,一件货物运送1个单位距离的代价是1。求把所有货物装进仓库的最小代价。

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstdio>
 6 #include<algorithm>
 7 #include<string>
 8 #include<map>
 9 #include<queue>
10 #include<vector>
11 #include<stack>
12 #define ll long long
13 #define maxn 4001000
14 #define lson l,m,rt<<1
15 #define rson m+1,r,rt<<1|1
16 #define rep(i,a,b) for(int i=a;i<=b;i++)
17 #define SWAP(x,y,t) ( (t)=(x),(x)=(y),(y)=(t) )
18 const int N=1000100;
19 ll f[N],x[N],p[N],c[N],sp[N],px[N],n,L,j,q[N],tail,head;
20 inline double X(ll i) {return sp[i];}
21 inline double Y(ll i) {return f[i]+px[i];}
22 inline double slope(ll i,ll j){return (Y(j)-Y(i))/(X(j)-X(i));}
23 using namespace std;
24 int main()
25 {
26     scanf("%lld",&n);head=tail=1;q[1]=0;sp[0]=px[0]=0;
27     rep(i,1,n) scanf("%lld%lld%lld",&x[i],&p[i],&c[i]);
28     rep(i,1,n) sp[i]=sp[i-1]+p[i];
29     rep(i,1,n) px[i]=px[i-1]+p[i]*x[i];
30     rep(i,1,n)
31     {
32         //printf("%.2lf %lld %lld %.lf %.lf\n",slope(q[head],q[head+1]),x[i],tail,Y(1),X(1));
33         while(head<tail && slope(q[head],q[head+1])<x[i]) head++;
34         j=q[head];f[i]=f[j]+(sp[i]-sp[j])*x[i]-(px[i]-px[j])+c[i];
35         //printf("%lld %lld\n",j,f[i]);
36         while(head<tail&& slope(q[tail-1],q[tail])>slope(q[tail],i)) tail--;
37         q[++tail]=i;    
38     }
39     printf("%lld\n",f[n]);
40 } 
View Code

 

3.BZOJ  1597

题意:给出n块土地,给出每块土地的长和宽,可以将n块土地分成若干组,每一组的费用是组中的长最大的土地的长与宽最大的土地的宽的乘积,求出将n块分成若干组的最小费用

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstdio>
 6 #include<algorithm>
 7 #include<string>
 8 #include<map>
 9 #include<queue>
10 #include<vector>
11 #include<stack>
12 #define ll long long
13 #define maxn 4001000
14 #define lson l,m,rt<<1
15 #define rson m+1,r,rt<<1|1
16 #define rep(i,a,b) for(int i=a;i<=b;i++)
17 #define SWAP(x,y,t) ( (t)=(x),(x)=(y),(y)=(t) )
18 const int N=1000100;
19 struct node{ll x,y;}a[101000];
20 ll f[N],x[N],p[N],c[N],sp[N],px[N],n,L,j,q[N],tail,head;
21 inline double X(ll i) {return a[i+1].x;}
22 inline double Y(ll i) {return f[i];}
23 inline double slope(ll i,ll j){return (Y(j)-Y(i))/(X(j)-X(i));}
24 bool cmp(node a,node b)
25 {
26     return a.x>b.x||(a.x==b.x&&a.y>b.y);
27 }
28 using namespace std;
29 int main()
30 {
31     scanf("%lld",&n);head=tail=1;q[1]=0;
32     rep(i,1,n) scanf("%lld%lld",&a[i].x,&a[i].y);
33     sort(a+1,a+1+n,cmp);
34     int cnt=0;
35     rep(i,1,n) if(a[i].y>a[cnt].y) a[++cnt]=a[i];
36     rep(i,1,cnt)
37     {
38         while(head<tail && slope(q[head],q[head+1])>-a[i].y) head++;
39         j=q[head];f[i]=f[j]+a[i].y*a[j+1].x;
40         //printf("%lld %lld\n",j,f[i]);
41         while(head<tail&& slope(q[tail-1],q[tail])<slope(q[tail],i)) tail--;
42         q[++tail]=i;    
43     }
44     printf("%lld\n",f[cnt]);
45 } 
View Code

4.BZOJ 1911

题意:有一些排列好的士兵,现在要把他们组成一些队伍,每个队伍的战斗力为ax^2 + bx + c,其中x是队伍的权值和。

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstdio>
 6 #include<algorithm>
 7 #include<string>
 8 #include<map>
 9 #include<queue>
10 #include<vector>
11 #include<stack>
12 #define ll long long
13 #define maxn 4001000
14 #define lson l,m,rt<<1
15 #define rson m+1,r,rt<<1|1
16 #define rep(i,a,b) for(int i=a;i<=b;i++)
17 #define SWAP(x,y,t) ( (t)=(x),(x)=(y),(y)=(t) )
18 const int N=1000100;
19 ll f[N],s[N],p[N],n,L,j,q[N],tail,head,a,b,c;
20 inline double X(ll i) {return s[i];}
21 inline double Y(ll i) {return f[i]+a*s[i]*s[i]-b*s[i];}
22 inline double slope(ll i,ll j){return (Y(j)-Y(i))/(X(j)-X(i));}
23 using namespace std;
24 int main()
25 {
26     scanf("%lld",&n);head=tail=1;q[1]=0;
27     scanf("%lld %lld %lld",&a,&b,&c);
28     rep(i,1,n) scanf("%lld",&s[i]),s[i]+=s[i-1];
29     rep(i,1,n)
30     {
31         while(head<tail && slope(q[head],q[head+1])>2*a*s[i]) head++;
32         j=q[head];f[i]=f[j]+a*(s[i]-s[j])*(s[i]-s[j])+b*(s[i]-s[j])+c;
33         //printf("%lld %lld\n",j,f[i]);
34         while(head<tail&& slope(q[tail-1],q[tail])<slope(q[tail],i)) tail--;
35         q[++tail]=i;    
36     }
37     printf("%lld\n",f[n]);
38 } 
View Code

5.BZOJ 3156

题意:一条线上N个(检查)点,编号1~N,一个点j上可以建一个守卫塔花费为a[j],也可以选择放个木偶(为什么会是木偶= =),花费是这个点右边建的第一个守卫塔i到这个点的距离,即i-j。问最小花费。

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstdio>
 6 #include<algorithm>
 7 #include<string>
 8 #include<map>
 9 #include<queue>
10 #include<vector>
11 #include<stack>
12 #define ll long long
13 #define maxn 4001000
14 #define lson l,m,rt<<1
15 #define rson m+1,r,rt<<1|1
16 #define rep(i,a,b) for(int i=a;i<=b;i++)
17 #define SWAP(x,y,t) ( (t)=(x),(x)=(y),(y)=(t) )
18 const int N=1000100;
19 ll f[N],s[N],p[N],n,L,q[N],tail,head,a[N],b,c;
20 inline double X(ll i) {return i;}
21 inline double Y(ll i) {return f[i]+s[i];}
22 inline double slope(ll i,ll j){return (Y(j)-Y(i))/(X(j)-X(i));}
23 using namespace std;
24 int main()
25 {
26     scanf("%lld",&n);head=tail=1;q[1]=0;
27     rep(i,1,n) scanf("%lld",&a[i]);
28     rep(i,1,n) s[i]=s[i-1]+i;
29     rep(i,1,n)
30     {
31         while(head<tail && slope(q[head],q[head+1])<i) head++;
32         int j=q[head];f[i]=f[j]+1ll*i*(i-j)-(s[i]-s[j])+a[i];
33         //printf("%lld %lld\n",j,f[i]);
34         while(head<tail&& slope(q[tail-1],q[tail])>slope(q[tail],i)) tail--;
35         q[++tail]=i;    
36     }
37     printf("%lld\n",f[n]);
38 } 
View Code

6.BZOJ 3437

题意:有n牧场排成一行,标号从1~n,每个牧场都可以放一个控制站,在第i个牧场放控制站需要花费a[i],控制站能够控制从它开始一直到它左边最靠近它的控制站之间的所有牧场,每个牧场放养量是b[i],这个牧场被它右侧离它最近控制站控制所需要支出的花费是它到牧场的距离d*b[j],在保证所有牧场都被控制的情况下,求最小花费

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstdio>
 6 #include<algorithm>
 7 #include<string>
 8 #include<map>
 9 #include<queue>
10 #include<vector>
11 #include<stack>
12 #define ll long long
13 #define maxn 4001000
14 #define lson l,m,rt<<1
15 #define rson m+1,r,rt<<1|1
16 #define rep(i,a,b) for(int i=a;i<=b;i++)
17 #define SWAP(x,y,t) ( (t)=(x),(x)=(y),(y)=(t) )
18 const int N=1000100;
19 ll f[N],s[N],p[N],n,L,q[N],tail,head,a[N],b[N],c;
20 inline double X(ll i) {return p[i];}
21 inline double Y(ll i) {return f[i]+s[i];}
22 inline double slope(ll i,ll j){return (Y(j)-Y(i))/(X(j)-X(i));}
23 using namespace std;
24 int main()
25 {
26     scanf("%lld",&n);head=tail=1;q[1]=0;
27     rep(i,1,n) scanf("%lld",&a[i]);
28     rep(i,1,n) scanf("%lld",&b[i]); 
29     rep(i,1,n) s[i]=s[i-1]+1ll*i*b[i];
30     rep(i,1,n) p[i]=p[i-1]+b[i];
31     rep(i,1,n)
32     {
33         while(head<tail && slope(q[head],q[head+1])<i) head++;
34         int j=q[head];f[i]=f[j]+1ll*i*(p[i]-p[j])-(s[i]-s[j])+a[i];
35         //printf("%lld %lld\n",j,f[i]);
36         while(head<tail&& slope(q[tail-1],q[tail])>slope(q[tail],i)) tail--;
37         q[++tail]=i;    
38     }
39     printf("%lld\n",f[n]);
40 } 
View Code

7.BZOJ 4518

题意:给你一个长为n的序列,要求将这个序列分成m段,使得每段内数字之和构成的方差最小.输出这个最小方差与m2的乘积

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstdio>
 6 #include<algorithm>
 7 #include<string>
 8 #include<map>
 9 #include<queue>
10 #include<vector>
11 #include<stack>
12 #define ll long long
13 #define maxn 4001000
14 #define lson l,m,rt<<1
15 #define rson m+1,r,rt<<1|1
16 #define rep(i,a,b) for(int i=a;i<=b;i++)
17 #define SWAP(x,y,t) ( (t)=(x),(x)=(y),(y)=(t) )
18 const int N=4000;
19 ll f[N][N],s[N],p[N],n,m,L,q[N],tail,head,a[N],b[N],c,k;
20 inline double X(ll i) {return s[i];}
21 inline ll sqr(ll i) {return i*i;}
22 inline double Y(ll i) {return f[k-1][i]+1ll*m*m*s[i]*s[i]+2ll*s[n]*m*s[i];}
23 inline double slope(ll i,ll j){return (Y(j)-Y(i))/(X(j)-X(i));}
24 using namespace std;
25 int main()
26 {
27     scanf("%lld%lld",&n,&m);
28     rep(i,1,n) scanf("%lld",&a[i]),s[i]=s[i-1]+a[i];
29     memset(f,63,sizeof(f));f[0][0]=0;
30     for(k=1;k<=m;k++)
31     {
32     head=tail=1;q[1]=0;
33         rep(i,1,n)
34         {
35             while(head<tail && slope(q[head],q[head+1])<2ll*m*m*s[i]) head++;
36             int j=q[head];f[k][i]=f[k-1][j]+sqr(1ll*m*(s[i]-s[j])-s[n]);
37             //printf("%lld %lld\n",j,f[k][i]);
38             while(head<tail&& slope(q[tail-1],q[tail])>slope(q[tail],i)) tail--;
39             q[++tail]=i;    
40         }
41     }
42     printf("%lld\n",f[m][n]/m);
43 } 
View Code

 

posted @ 2018-10-30 19:40  The-Pines-of-Star  阅读(222)  评论(0编辑  收藏  举报