BZOJ 3675: [Apio2014]序列分割
2017-11-02 20:38
211 查看
题意
小H最近迷上了一个分隔序列的游戏。在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列。为了得到k+1个子序列,小H需要重复k次以下的步骤:1.小H首先选择一个长度超过1的序列(一开始小H只有一个长度为n的序列——也就是一开始得到的整个序列);
2.选择一个位置,并通过这个位置将这个序列分割成连续的两个非空的新序列。
每次进行上述步骤之后,小H将会得到一定的分数。这个分数为两个新序列中元素和的乘积。小H希望选择一种最佳的分割方式,使得k轮之后,小H的总得分最大。
输入
输入第一行包含两个整数n,k (k+1≤n)。第二行包含n个非负整数a1,a2,…,an(0≤ai≤104),表示一开始小H得到的序列。
输出
输出第一行包含一个整数,为小H可以得到的最大分数。样例输入
7 3 4 1 3 4 0 2 3
样例输出
108
我们首先可以发现交换切割顺序不会影响答案
然后可以得到式子
令fi,k表示在取到第i个数时切割k次的最大分数
则 fi,k=max{fj,k−1+sumj+1,i×sumi+1,n}
(sumi,k 表示 ∑kj=iaj )
令si=∑ij=1aj
对于一个固定的k, 令gi=fi,k−1, 则fi,k=max{gj+(si−sj)×(sn−si)}
化简得
fi,k=max{gj−s2i+si×sn−sj×sn} =max{gj−sj×sn}−s2i+si×sn
对于两个决策 j,k (j>k)
决策j比k优当且仅当 gj−gk>(sn−si)×(sj−sk)
即
gj+gksj−sk>sn−si
故可以进行斜率优化
因为序列中的数有可能为0,所以需要注意斜率不存在的情况。
因为只有128M内存,需要滚动f数组
#include <bits/stdc++.h> using namespace std; #define N 100010 #define ll long long deque s[210]; ll sum ,f[2] ; double calc(int j,int k,int p) { //j>k if(sum[j]==sum[k]) return -1e10; return (double)(f[p & 1][j]-f[p & 1][k])/(double)(sum[j]-sum[k]); } int a ; int main() { //freopen("3675.in","r",stdin); int n,k; scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; } for(int i=1;i<=k;i++) { s[i].push_back(1); f[i&1][1]=sum[1]*(sum -sum[1]); } s[0].push_back(0); for(int j=1;j<=k;j++) { for(int i=2;i<=n;i++){ while(s[j-1].size()>1&&calc(s[j-1][s[j-1].size()-2],s[j-1].back(),j-1)>(sum -sum[i])) { s[j-1].pop_back(); } f[j & 1][i]=f[(j-1) & 1][s[j-1].back()]+(sum -sum[i])*(sum[i]-sum[s[j-1].back()]); while(s[j].size()>1&&calc(i,s[j].front(),j)>=calc(s[j].front(),s[j][1],j)) { s[j].pop_front(); } s[j].push_front(i); } } ll ans=0; for(int i=1;i<=n;i++) { ans=max(ans,f[k & 1][i]); } printf("%lld\n",ans); }
在UOJ上也有一道一样的题,需要输出方案,但空间给的256M
可以直接开一个数组记录答案
#include <bits/stdc++.h> using namespace std; #define N 100010 #define ll long long deque s[210]; ll sum ,f[2] ; int pre[210] ; double calc(int j,int k,int p) { //j>k if(sum[j]==sum[k]) return -999999; return (double)(f[p & 1][j]-f[p & 1][k])/(double)(sum[j]-sum[k]); } int a ; int main() { freopen("3675.in","r",stdin); int n,k; scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; } /*for(int i=1;i<=k;i++) { s[i].push_back(1); f[i&1][1]=sum[1]*(sum -sum[1]); }*/ // s[1].push_back(1); f[1&1][1]=sum[1]*(sum -sum[1]); s[0].push_back(0); // f[1][1]=sum[1]*(sum -sum[1]); for(int j=1;j<=k;j++) { for(int i=j;i1&&calc(s[j-1][s[j-1].size()-2],s[j-1].back(),j-1)>(sum -sum[i])) { s[j-1].pop_back(); } f[j & 1][i]=f[(j-1) & 1][s[j-1].back()]+(sum -sum[i])*(sum[i]-sum[s[j-1].back()]); pre[j][i]=s[j-1].back(); while(s[j].size()>1&&calc(i,s[j].front(),j)>=calc(s[j].front(),s[j][1],j)) { s[j].pop_front(); } s[j].push_front(i); } } ll ans=0; int pos=0; for(int i=1;i=ans) pos=i; ans=max(ans,f[k & 1][i]); } printf("%lld\n",ans); for(int i=k;i>=1;i--) { printf("%d ",pos); if(pre[i][pos]!=0) pos=pre[i][pos]; } // printf("%d",pos); }
查看原文:https://gyming.org/?p=228
相关文章推荐
- bzoj3675: [Apio2014]序列分割【斜率优化dp】
- 【动态规划17】bzoj3675 [Apio2014]序列分割(斜率优化)
- 【BZOJ】3675: [Apio2014]序列分割
- bzoj3675 [Apio2014]序列分割
- 【斜率优化】bzoj3675-[Apio2014]序列分割&&Uoj104
- [Bzoj3675][Apio2014]序列分割(斜率优化)
- [BZOJ3675][Apio2014]序列分割-斜率优化-动态规划
- BZOJ 3675 [Apio2014] 序列分割 斜率优化
- BZOJ 3675 APIO2014 序列分割 斜率优化
- bzoj 3675: [Apio2014]序列分割 斜率优化dp
- bzoj3675: [Apio2014]序列分割
- 动态规划(斜率优化):BZOJ 3675 [Apio2014]序列分割
- BZOJ3675 [APIO2014]序列分割(斜率优化模板)
- BZOJ 3675 [Apio2014]序列分割 动态规划+斜率优化
- BZOJ3675 [Apio2014]序列分割 【斜率优化dp】
- [BZOJ3675][Apio2014]序列分割(斜率优化DP)
- [bzoj 3675--Apio2014]序列分割
- BZOJ3675 [Apio2014]序列分割 【斜率优化dp】
- BZOJ 3675: [Apio2014]序列分割
- [BZOJ 3675][APIO 2014]序列分割(斜率优化DP)