P4983-忘情【wqs二分,斜率优化】
正題
題目鏈接:https://www.luogu.com.cn/problem/P4983
題目大意
給出長度為nnn的序列xxx,記平均數為xˉ\bar{x}xˉ,要求將序列分成mmm段。
每一段[l,r][l,r][l,r]的值為
((∑i=lrxi×xˉ)+xˉ)2xˉ2\frac{((\sum_{i=l}^rx_i\times \bar x)+\bar x)^2}{\bar x^2}xˉ2((∑i=lr?xi?×xˉ)+xˉ)2?
求所有段的值和最小
1≤m≤n≤105,1≤xi≤10001\leq m\leq n\leq 10^5,1\leq x_i\leq 10001≤m≤n≤105,1≤xi?≤1000
解題思路
直接除以xˉ2\bar x^2xˉ2就是最小化(∑i=lrxi+1)2(\sum_{i=l}^rx_i+1)^2(∑i=lr?xi?+1)2的和。
然后這個問題是下凸函數,設f(i)f(i)f(i)表示恰好分成iii段,那么顯然段數越多答案越小而且每次減少的越少。
所以我們可以用wqswqswqs二分給每次分一個段加上一個權值valvalval。
那么現在的轉移就是
Fi=min{Fj+(si?sj+1)2+val}(j<i)F_i=min\{F_j+(s_i-s_j+1)^2+val\}(j<i)Fi?=min{Fj?+(si??sj?+1)2+val}(j<i)
這是經典的斜率優化不過多贅述。
時間復雜度O(nlog?W)O(n\log W)O(nlogW)(WWW表示二分值域)
code
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=1e5+10; ll n,m,s[N],f[N],g[N],x[N],y[N],q[N]; ll count(ll l,ll r) {return f[l]+(s[r]-s[l]+1)*(s[r]-s[l]+1);} ll xj(ll p,ll q,ll z) {return (x[p]-x[z])*(y[q]-y[z])-(x[q]-x[z])*(y[p]-y[z]);} ll check(ll val){int head=1,tail=0;q[++tail]=0;for(ll i=1;i<=n;i++){while(head<tail&&2ll*s[i]*(x[q[head+1]]-x[q[head]])>(y[q[head+1]]-y[q[head]]))head++;f[i]=count(q[head],i)+val;g[i]=g[q[head]]+1;y[i]=f[i]+s[i]*s[i]-2*s[i];x[i]=s[i];while(head<tail&&xj(i,q[tail],q[tail-1])>=0)tail--;q[++tail]=i;}return g[n]; } signed main() {scanf("%lld%lld",&n,&m);for(ll i=1;i<=n;i++)scanf("%lld",&s[i]),s[i]+=s[i-1];ll l=0,r=1e18;while(l<=r){ll mid=(l+r)>>1;if(check(mid)<=m)r=mid-1;else l=mid+1;}check(l);printf("%lld\n",f[n]-l*m);return 0; }總結
以上是生活随笔為你收集整理的P4983-忘情【wqs二分,斜率优化】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 日产汽车中国区 10 月销量达 7327
- 下一篇: P5048-[Ynoi2019 模拟赛]