HDU 2829 Lawrence(斜率DP)
2015-09-18 15:05
405 查看
题意:给n(1<=n<=1000)个数,要将其分成m + 1(0<=m<n)组,要求每组数必须是连续的而且要求得到的价值最小。一组数的价值定义为该组内任意两个数乘积之和,如果某组中仅有一个数,那么该组数的价值为0。
思路:设sv[i][j]为区间[i,j]之间的价值,那么我们可以得到一个状态转移方程
dp[i][j] = min(d[i-1][k]+sv[k+1][j]),dp[i][j]表示前j个数放i个间隔的最小值,
可以发现如果不优化的话时间复杂度为O(n*n*n)无法承受,我们要优化首先要把sv[k+1][j]转化成一个包含k和包含j和包含jk的多项式的乘积,
可以发现sv[k+1][j] = sv[1][j] - sv[1][k] - sum[k]*(sum[j]-sum[k]),然后我们可以发现出现了只和k,j有关的项和包含j的项乘以包含k的项,那么我们就可以用斜率DP来优化了。
题意:给n(1<=n<=1000)个数,要将其分成m + 1(0<=m<n)组,要求每组数必须是连续的而且要求得到的价值最小。一组数的价值定义为该组内任意两个数乘积之和,如果某组中仅有一个数,那么该组数的价值为0。
思路:设sv[i][j]为区间[i,j]之间的价值,那么我们可以得到一个状态转移方程
dp[i][j] = min(d[i-1][k]+sv[k+1][j]),dp[i][j]表示前j个数放i个间隔的最小值,
可以发现如果不优化的话时间复杂度为O(n*n*n)无法承受,我们要优化首先要把sv[k+1][j]转化成一个包含k和包含j和包含jk的多项式的乘积,
可以发现sv[k+1][j] = sv[1][j] - sv[1][k] - sum[k]*(sum[j]-sum[k]),然后我们可以发现出现了只和k,j有关的项和包含j的项乘以包含k的项,那么我们就可以用斜率DP来优化了。
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue> #include<stack> #include<string> #include<map> #include<set> #include<ctime> #define eps 1e-6 #define LL long long #define pii pair<int, int> //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const int MAXN = 1000 + 5; int n, m; int a[MAXN]; LL Sum[MAXN], sv[MAXN][MAXN], dp[MAXN][MAXN]; int Q[MAXN], h, t; LL getY(int k, int j, int i) { return dp[i][k]-sv[1][k]+Sum[k]*Sum[k] - dp[i][j]+sv[1][j]-Sum[j]*Sum[j]; } LL getX(int k, int j) { return Sum[k]-Sum[j]; } int main() { //freopen("input.txt", "r", stdin); while(scanf("%d%d", &n, &m)==2 && n) { int tmp; for(int i = 1; i <= n; i++) scanf("%d", &a[i]), Sum[i]=Sum[i-1]+a[i]; for(int i = 1; i <= n; i++) { for(int j = i+1; j <= n; j++) sv[i][j] = sv[i][j-1]+a[j]*(Sum[j-1]-Sum[i-1]); } for(int j = 1; j <= n; j++) dp[0][j] = sv[1][j]; for(int i = 1; i <= m; i++) { h = 1, t = 0; Q[++t] = i; for(int j = i+1; j <= n; j++) { //if(i==2&&j==4) cout << Q[t] << endl; while(t>h && getY(Q[h+1], Q[h], i-1)<=Sum[j]*getX(Q[h+1], Q[h])) h++; //if(i==2&&j==4) cout << getY(Q[h+1], Q[h], i-1) << endl << Sum[j]*getX(Q[h+1], Q[h]) << endl; //if(i==2&&j==4) cout << Q[h] << endl; dp[i][j] = dp[i-1][Q[h]] + sv[Q[h]+1][j]; while(t>h && getY(j, Q[t], i-1)*getX(Q[t], Q[t-1])<=getY(Q[t],Q[t-1], i-1)*getX(j, Q[t])) t--; Q[++t] = j; //cout << i << " " << j << " " << dp[i][j] << endl; } } cout << dp[m] << endl; } return 0; }
相关文章推荐
- django signal
- 左移运算符
- APK反编译
- 复习java web之jsp入门_El表达式_JSTL标签库
- 黑马程序员-Java基础学习第七天总结
- 面试题 33
- CentOS6.4安装Bugzilla
- Java和C++程序在编译和运行上有什么区别
- S3C2440驱动移植——AT24C02(EEPROM)移植
- Proxy
- 苹果 xCode7 dmg 和其他工具dmg文件的官方下载地址
- Mac下SVN提交xcode工程代码需要过滤的文件
- iOS开发网络篇—NSURLConnection基本使用
- 分析产品数据时需要注意哪些坑?
- 配置和使用ShareActionProvider
- eclipse导入本地项目SVN信息丢失的问题
- 【python txt2xls】个人开发的python文本转表格工具txt2xls
- 开源驰骋工作流引擎ccbpm(CCFlow与JFlow)对bpmn2.0的支持
- openfire删除
- 命令模式