P3648-[APIO2014]序列分割【斜率优化】
正題
題目鏈接:https://www.luogu.com.cn/problem/P3648
題目大意
nnn個數(shù)字的序列,分割kkk次,每次的權(quán)值是左右兩塊數(shù)字的乘積。求最大權(quán)值和分割方案。
解題思路
顯然分割順序不會影響結(jié)果,一個分割方式的答案是每一塊與其他塊的乘積之和。
考慮dpdpdp,fi,jf_{i,j}fi,j?表示第iii次分割,到第jjj個時的方案數(shù),有轉(zhuǎn)移
fi,j=max{fi?1,k+(sj?sk)?sk}f_{i,j}=max\{f_{i-1,k}+(s_j-s_k)*s_k\}fi,j?=max{fi?1,k?+(sj??sk?)?sk?}
考慮兩個方案k′<kk'<kk′<k的優(yōu)劣性
fi?1,k+sj?sk?sk2>fi?1,k′+sj?sk′?sk′2f_{i-1,k}+s_j*s_k-s_k^2>f_{i-1,k'}+s_j*s_{k'}-s_{k'}^2fi?1,k?+sj??sk??sk2?>fi?1,k′?+sj??sk′??sk′2?
fi?1,k+sj?sk?fi?1,k′+sk′2>sj?(sk′?sk)f_{i-1,k}+s_j*s_k-f_{i-1,k'}+s_{k'}^2>s_j*(s_{k'}-s_{k})fi?1,k?+sj??sk??fi?1,k′?+sk′2?>sj??(sk′??sk?)
fi?1,k+sj?sk?fi?1,k′+sk′2sk′?sk<sj\frac{f_{i-1,k}+s_j*s_k-f_{i-1,k'}+s_{k'}^2}{s_{k'}-s_{k}}<s_jsk′??sk?fi?1,k?+sj??sk??fi?1,k′?+sk′2??<sj?
因?yàn)?span id="ze8trgl8bvbq" class="katex--inline">sjs_jsj?遞增,所以單調(diào)隊列維護(hù)一個上突殼即可
然后記錄一下前驅(qū)輸出方案
時間復(fù)雜度O(nk)O(nk)O(nk)
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=110000; ll n,k,q[N],fa[210][N],s[N],f[2][N]; double slope(ll z,ll x,ll y){if(s[y]==s[x])return -1e18;return (f[z][x]-f[z][y]-s[x]*s[x]+s[y]*s[y])/(double)(s[y]-s[x]); } int main() {scanf("%lld%lld",&n,&k);for(ll i=1;i<=n;i++)scanf("%lld",&s[i]),s[i]+=s[i-1];memset(f,0,sizeof(f));for(ll i=1;i<=k;i++){ll head=1,tail=0;memset(f[i&1],0,sizeof(f[i&1]));for(ll j=1;j<=n;j++){while(head<tail&&slope(~i&1,q[head],q[head+1])<=s[j])head++;f[i&1][j]=0;if(head<=tail){ll x=q[head];fa[i][j]=x;f[i&1][j]=f[~i&1][x]+(s[j]-s[x])*s[x];}while(head<tail&&slope(~i&1,q[tail],q[tail-1])>=slope(~i&1,j,q[tail]))tail--;q[++tail]=j;}}printf("%lld\n",f[k&1][n]);for(ll i=k,w=fa[k][n];i;w=fa[--i][w])printf("%lld ",w); }總結(jié)
以上是生活随笔為你收集整理的P3648-[APIO2014]序列分割【斜率优化】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑不会进入自动休眠模式如何不让电脑进入
- 下一篇: 豪华车市场酣战,月破4万的理想能过BBA