BZOJ 3675 [Apio2014] 序列分割 斜率优化
2017-01-12 15:11
302 查看
题目大意:将一个长度为n的非负整数序列分割成k+1个非空的子序列,即将序列切割k次。首先选择一个长度超过1的序列;然后选择一个位置,并通过这个位置将这个序列分割成连续的两个非空的新序列。每次进行上述步骤之后,将会得到一定的分数。这个分数为两个新序列中元素和的乘积。求最大得分。
首先,对于一段序列想分成A|B|C|D四份,先分成A|BCD与先AB|CD的得分是相同的。这样这个问题就具有了子问题的性质,可以DP。设状态f(i,j)代表在i处分割、已经分割了k次的最大得分,状态转移方程为
考虑怎么优化。
设P为f(i,k)的一个可能的值。
将P代入,max去掉,将式子变形,得到
设x=sum(j),y=-sum(j)2+f(j,k-1)(偷懒没用公式编辑器凑合看一下),将式子变为
很明显的一个y=kx+b的形式。
k=sum(i)为定值,想让P最大,也就是让(-P)最小,即最小化截距.
可以发现所选的点一定在下凸包上(自行画个图理解一下吧我不画了…)
并且发现查询的斜率单调,维护一个单调队列,时间复杂度O(kn)
首先,对于一段序列想分成A|B|C|D四份,先分成A|BCD与先AB|CD的得分是相同的。这样这个问题就具有了子问题的性质,可以DP。设状态f(i,j)代表在i处分割、已经分割了k次的最大得分,状态转移方程为
//O(kn2)TLE #include <cstdio> #include <algorithm> #include <cstring> #define N 100005 #define M 205 using namespace std; typedef long long LL; LL sum ,f[2] ; int main() { int n,m,x; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&x) , sum[i]=sum[i-1]+x; int o=0; for(int i=1;i<=m;i++) { memset(f[o],0,sizeof f[o]); for(int j=1;j<=n;j++) for(int k=1;k<j;k++) f[o][j]=max(f[o][j],(sum[j]-sum[k])*sum[k]+f[o^1][k]); o^=1; } printf("%lld\n",f[o^1] ); return 0; }
考虑怎么优化。
设P为f(i,k)的一个可能的值。
将P代入,max去掉,将式子变形,得到
设x=sum(j),y=-sum(j)2+f(j,k-1)(偷懒没用公式编辑器凑合看一下),将式子变为
很明显的一个y=kx+b的形式。
k=sum(i)为定值,想让P最大,也就是让(-P)最小,即最小化截距.
可以发现所选的点一定在下凸包上(自行画个图理解一下吧我不画了…)
并且发现查询的斜率单调,维护一个单调队列,时间复杂度O(kn)
#include <cstdio> #include <algorithm> #include <cstring> #define N 100005 #define M 205 #define INF 2147483647 using namespace std; typedef long long LL; struct Point { LL x,y; double slope; Point(LL a,LL b):x(a),y(b),slope(0.0){} Point(){} //get_slope double operator ^ (const Point& rhs) const { if(x==rhs.x) return (rhs.y > y ? INF : -INF); return (double)(y-rhs.y)/(x-rhs.x); } }q ; int l,r; LL sum ,f[2] ; void Insert(Point o) { double s=0; while(l<r) { s=q[r-1]^o; if(q[r-1].slope>s) r--; else break; } q[r++]=o; q[r-1].slope=s; return ; } LL get_ans(double k) { while(l!=r-1) { if(q[l+1].slope<k) l++; else break; } return k*q[l].x-q[l].y; } int main() { int n,m,x; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&x) , sum[i]=sum[i-1]+x; int o=0; for(int i=1;i<=m;i++) { l=r=1; for(int j=2;j<=n;j++) { Insert(Point(sum[j-1],sum[j-1]*sum[j-1]-f[o^1][j-1])); f[o][j]=get_ans(sum[j]); } o^=1; } printf("%lld\n",f[o^1] ); return 0; }
相关文章推荐
- BZOJ 3675: [Apio2014]序列分割( dp + 斜率优化 )
- 【BZOJ3675】[Apio2014]序列分割【斜率优化】
- bzoj3675[Apio2014]序列分割 斜率优化dp
- bzoj3675: [Apio2014]序列分割【斜率优化dp】
- bzoj 3675: [Apio2014]序列分割(斜率优化)
- BZOJ3675 [APIO2014]序列分割(斜率优化模板)
- BZOJ3675 [Apio2014]序列分割 【斜率优化dp】
- [BZOJ3675][Apio2014]序列分割-斜率优化-动态规划
- 【BZOJ3675】【APIO2014】序列分割 [斜率优化DP]
- 【动态规划17】bzoj3675 [Apio2014]序列分割(斜率优化)
- bzoj 3675: [Apio2014]序列分割 斜率优化dp
- [省选前题目整理][BZOJ 3675][APIO 2014]序列分割(斜率优化DP)
- bzoj-3675 序列分割APIO2014 斜率优化dp
- BZOJ 3675 APIO2014 序列分割 斜率优化
- [BZOJ 3675][APIO 2014]序列分割(斜率优化DP)
- bzoj3675 [APIO2014] 序列分割(斜率优化)
- [Bzoj3675][Apio2014]序列分割(斜率优化)
- [BZOJ3675][Apio2014]序列分割(斜率优化dp)
- 【BZOJ3675】【APIO2014】序列分割(斜率优化DP)
- BZOJ 3675 APIO2014 序列分割 斜率优化DP