斜率优化DP
来源:互联网 发布:国产电视机 知乎 编辑:程序博客网 时间:2024/06/10 10:06
- HDU - 3507 Print Article
- HDU - 2829 Lawrence
- HDU - 1300 Pearls
- HDU 3480 Division
- HYSBZ 1010 玩具装箱toy
- HYSBZ - 1096 仓库建设
HDU - 3507
入门题。
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>using namespace std;#define ll long longconst int maxn = 5e5 + 10;ll d[maxn],sum[maxn],dp[maxn];int n,m;ll getx(int j,int k){ return dp[j] + sum[j]*sum[j] - (dp[k] + sum[k]*sum[k]); }ll gety(int j,int k){ return 2*sum[j]-2*sum[k]; }ll getval(int i,int j){ return dp[j] + (sum[i]-sum[j])*(sum[i]-sum[j]) + m; }int que[maxn];int main(){ while(~scanf("%d%d",&n,&m)) { for(int i = 1; i <= n; i++) { scanf("%I64d",&d[i]); sum[i] = d[i]; if(i) sum[i] += sum[i-1]; dp[i] = 0; } int head = 0,tail = 1; que[0] = 0; for(int i = 1; i <= n; i++) { while(tail > head+1 && getx(que[head+1],que[head]) <= sum[i]*gety(que[head+1],que[head])) ++head; dp[i] = getval(i,que[head]); while(tail > head+1 && getx(i,que[tail-1])*gety(que[tail-1],que[tail-2]) <= getx(que[tail-1],que[tail-2])*gety(i,que[tail-1])) tail--; que[tail++] = i; } printf("%I64d\n", dp[n]); } return 0;}
HDU - 2829
题目大意:给你m个炸弹炸铁路,最后问你铁路最小价值和是多少。
思路:可以推出一个很神奇的式子:
所以有:
然后设
发现这个fn[i,k] = fn[i] - fn[k-1],可以O(1)查询,满足区间减法!所以这个时候我们的前提条件就准备好啦。
代码我是设的
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>using namespace std;const int maxn = 1e3+10;#define ll long longint d[maxn];ll dp[maxn][maxn],fn[maxn],sum[maxn];ll getval(int i,int k,int j){ ll temp = fn[i] - fn[k] - sum[k+1]*(sum[i+1]-sum[k+1]); return temp+dp[k][j-1];}ll getx(int j,int k,int lev){ ll a = dp[j][lev-1] - fn[j] + sum[j+1]*sum[j+1]; ll b = dp[k][lev-1] - fn[k] + sum[k+1]*sum[k+1]; return a-b;}int que[maxn];ll gety(int j,int k){ return sum[j+1] - sum[k+1]; }int n,m;int main(){ //freopen("D:\\in.txt","r",stdin); while(scanf("%d%d",&n,&m) && n+m) { for(int i = 1; i <= n; i++) scanf("%d",&d[i]); for(int i = 1; i <= n; i++) { sum[i] = d[i-1] + sum[i-1]; fn[i] = sum[i]*d[i] + fn[i-1]; } sum[n+1] = d[n] + sum[n]; for(int i = 1; i <= n; i++) dp[i][1] = getval(i,0,1); for(int j = 2; j <= m+1; j++) { int h = 0, t = 1; que[h] = j-1;que[t++] = j; for(int i = 0; i <= j; i++) dp[i][j] = 0; for(int i = j+1; i <= n;i++) { int T = sum[i+1]; while(h+1 < t && getx(que[h+1],que[h],j) <= T*gety(que[h+1],que[h])) h++; dp[i][j] = getval(i,que[h],j); while(h+1<t && getx(i,que[t-1],j)*gety(que[t-1],que[t-2]) <= getx(que[t-1],que[t-2],j)*gety(i,que[t-1])) t--; que[t++] = i; } } printf("%I64d\n",dp[n][m+1]); } return 0;}
HDU - 1300
题意:这题其实最难的是题意,其实我也就看了个大概
有n种珍珠,每种珍珠有一个需求量,有单价,排在前面的可以用后面的价格买,排在后面的不能用前面的价格买。买的时候是这个式子:
思路:先列dp方程
然后的事情就很简单了。
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>using namespace std;const int maxn = 105;int d[maxn],c[maxn];int sum[maxn];int dp[maxn],q[maxn];int getavl(int i,int k){ return dp[k] + c[i]*(sum[i]-sum[k] + 10);}int getx(int j,int k){ return dp[j]-dp[k]; }int gety(int j,int k){ return sum[j]-sum[k]; }int n;int main(){ int t; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i = 1; i <= n; i++) { scanf("%d%d",&d[i],&c[i]); sum[i] = d[i] + sum[i-1]; } int h = 0,t = 0; q[t++] = 0; for(int i = 1; i <= n; i++) { int T = c[i]; while(h+1<t && getx(q[h+1],q[h]) <= gety(q[h+1],q[h])*T) ++h; dp[i] = getavl(i,q[h]); while(h+1<t && getx(i,q[t-1])*gety(q[t-1],q[t-2]) <= getx(q[t-1],q[t-2])*gety(i,q[t-1])) --t; q[t++] = i; } cout << dp[n] << endl; } return 0;}
HDU - 3480
题意: 把一个序列分成m段,使每段的最大值减最小值的平方和最小。
思路:我们需要先排个序,然后再处理
可以推出dp方程:
由于数组很大,所以需要一下滚动数组。
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>using namespace std;const int maxn = 1e4 + 10;int d[maxn];int dp[maxn][2];int getval(int i,int k,int j){ int last = j==0?1:0; return dp[k][last] + (d[i]-d[k+1])*(d[i]-d[k+1]);}int getx(int j,int k,int th){ int last = th==0?1:0; return dp[j][last]+d[j+1]*d[j+1] - (dp[k][last] + d[k+1]*d[k+1]);}int gety(int j,int k){return d[j+1]-d[k+1];}int q[maxn];int n,m;int main(){ int t,kase=1; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++) scanf("%d",&d[i]); sort(d + 1, d + n + 1); int th = 0,last = 0; for(int i = 1; i <= n; i++) dp[i][0] = getval(i,0,th); for(int j = 2; j <= m; j++) { th = last?0:1; for(int i = 1; i <= j; i++) dp[i][th] = 0; int h = 0,t = 0; q[t++] = j-1; q[t++] = j; for(int i = j+1; i <= n; i++) { int T = d[i]*2; while(h+1<t && getx(q[h+1],q[h],th) <= T*gety(q[h+1],q[h])) h++; dp[i][th] = getval(i,q[h],th); while(h+1<t && getx(i,q[t-1],th)*gety(q[t-1],q[t-2]) <= getx(q[t-1],q[t-2],th)*gety(i,q[t-1])) t--; q[t++] = i; } last = th; } printf("Case %d: %d\n", kase++, dp[n][th]); } return 0;}
BZOJ - 1010
题意:中文题
思路:
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>using namespace std;#define ll long longconst int maxn = 5e4 + 10;ll d[maxn],sum[maxn],dp[maxn];int que[maxn];int n,m;ll getval(int i,int j){ ll temp = i - (j+1) + sum[i] - sum[j]; return (ll)dp[j] + (temp-m)*(temp-m);}ll getx(int j,int k){ ll a = dp[j] + (j+1+sum[j]+m)*(j+1+sum[j]+m); ll b = dp[k] + (k+1+sum[k]+m)*(k+1+sum[k]+m); return a-b;}ll gety(int j,int k){ return j+sum[j]-k-sum[k];}int main(){ scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++) { scanf("%lld",&d[i]); sum[i] = d[i]; sum[i] += sum[i-1]; dp[i] = 0; } int head = 0, tail = 1; que[0] = 0; for(int i = 1; i <= n; i++) { ll T = 2*(i+sum[i]); while(tail > head+1 && getx(que[head+1],que[head]) <= T*gety(que[head+1],que[head])) head++; dp[i] = getval(i,que[head]); while(tail > head+1 && getx(i,que[tail-1])*gety(que[tail-1],que[tail-2]) <= getx(que[tail-1],que[tail-2])*gety(i,que[tail-1])) tail--; que[tail++] = i; } printf("%lld\n",dp[n]); return 0;}
BZOJ - 1096
中文题+2
思路:
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>using namespace std;#define ll long longconst int maxn = 1e6 + 10;ll d[maxn][3];ll sum[maxn], fn[maxn];int que[maxn];ll dp[maxn];ll setval(int i,int k){ ll temp = dp[k] - fn[i] + fn[k] + d[i][0]*(sum[i]-sum[k]) + d[i][2]; return temp;}ll fx(int j,int k){ ll a = dp[j] + fn[j] ; ll b = dp[k] + fn[k] ; return a-b;}ll fy(int j,int k){ return sum[j] - sum[k];}int main(){ //freopen("D:\\in.txt","r",stdin); int n; scanf("%d",&n); for(int i = 1; i <= n; i++) { scanf("%lld%lld%lld",&d[i][0],&d[i][1],&d[i][2]); ll temp = d[i][0]*d[i][1]; fn[i] = temp; sum[i] = d[i][1]; fn[i] += fn[i-1]; sum[i] += sum[i-1]; } int h = 0,t = 1; que[0] = 0; for(int i = 1; i <= n; i++) { ll T = d[i][0]; while(h+1<t && fx(que[h+1],que[h]) <= fy(que[h+1],que[h])*T) h++; dp[i] = setval(i,que[h]); while(h+1<t && fx(i,que[t-1])*fy(que[t-1],que[t-2]) <= fx(que[t-1],que[t-2])*fy(i,que[t-1])) --t; que[t++] = i; } printf("%lld\n",dp[n]); return 0;}
- DP(斜率优化)
- 【斜率优化DP】Batch_Scheduling
- dp优化--斜率
- 斜率优化DP
- 斜率优化DP
- hdu3507斜率优化dp
- DP斜率优化总结
- hdu3480 斜率优化dp
- hdu3507 斜率优化dp
- 斜率优化DP
- 斜率优化DP 【pascal】
- 斜率优化DP
- dp 斜率优化
- 斜率优化 DP
- HDU_3669 斜率优化DP
- dp斜率优化
- DP斜率优化
- hdu4258 斜率优化dp
- Java面试绕不开的问题: Java中HashMap底层实现原理(JDK1.8)源码分析
- 多项式及其计算
- 浅析MySQL支持的数据类型
- 项目所得
- UVA
- 斜率优化DP
- 我的进步
- CGI与FastCGI的介绍
- 【POJ3744】Scout YYF I
- 2017 Multi-University Training Contest
- SAMBA服务器笔记
- ArrayList集合数据排序问题
- DOM(一)
- 理解C中复杂声明