ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P4983-忘情【wqs二分,斜率优化】

2021-07-13 07:33:44  阅读:215  来源: 互联网

标签:node P4983 bar leq int wqs 斜率 bool include


正题

题目链接:https://www.luogu.com.cn/problem/P4983


题目大意

给出长度为\(n\)的序列\(x\),记平均数为\(\bar{x}\),要求将序列分成\(m\)段。
每一段\([l,r]\)的值为

\[\frac{((\sum_{i=l}^rx_i\times \bar x)+\bar x)^2}{\bar x^2} \]

求所有段的值和最小

\(1\leq m\leq n\leq 10^5,1\leq x_i\leq 1000\)


解题思路

直接除以\(\bar x^2\)就是最小化\((\sum_{i=l}^rx_i+1)^2\)的和。

然后这个问题是下凸函数,设\(f(i)\)表示恰好分成\(i\)段,那么显然段数越多答案越小而且每次减少的越少。

所以我们可以用\(wqs\)二分给每次分一个段加上一个权值\(val\)。

那么现在的转移就是

\[F_i=min\{F_j+(s_i-s_j+1)^2+val\}(j<i) \]

这是经典的斜率优化不过多赘述。

时间复杂度\(O(n\log W)\)(\(W\)表示二分值域)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2100;
struct node{
	int l,r;
}q[110000];
int n,m,k,t,ans,p[N],st[N][26],ss[N][26],nxt[N],f[N][N],pre[N][N];
char T[N],S[N];
bool cmp(node x,node y)
{return x.l<y.l;}
int main()
{
	freopen("lcs.in","r",stdin);
	freopen("lcs.out","w",stdout);
	scanf("%s",T+1);m=strlen(T+1);
	scanf("%s",S+1);n=strlen(S+1);
	for(int i=1;i<=m;i++){
		for(int j=0;j<26;j++)
			st[i][j]=st[i-1][j]+(T[i]=='a'+j);
	}
	for(int i=1;i<=n;i++){
		for(int j=0;j<26;j++)
			ss[i][j]=ss[i-1][j]+(S[i]=='a'+j);
	}
	scanf("%d",&k);
	for(int i=1;i<=k;i++)
		scanf("%d%d",&q[i].l,&q[i].r),q[i].l++,q[i].r++;
	sort(q+1,q+1+k,cmp);
	int nowr=0,pr=0;
	for(int i=1;i<=k;i++){
		if(q[i].l>nowr){
			nxt[pr]=nowr;
			for(int j=nowr+1;j<q[i].l;j++)nxt[j]=j;
			pr=q[i].l;nowr=q[i].r;
		}
		else nowr=max(q[i].r,nowr);
	}
	nxt[pr]=nowr;
	for(int i=nowr+1;i<=n;i++)nxt[i]=i;
	for(int i=1;i<=n;i++)
		if(nxt[i])p[++t]=i;
	for(int i=1;i<=m;i++)
		for(int j=1;j<=t;j++){
			int l=p[j],r=nxt[l],L=i;
			for(int z=min(r-l,m-L);z>=0;z--){
				bool flag=1;
				for(int k=0;k<26;k++)
					if(ss[r][k]-ss[l-1][k]<st[L+z][k]-st[L-1][k])
						{flag=0;break;}
				if(flag){pre[i][j]=z+1;break;}
			}
		}
	for(int i=1;i<=m;i++)
		for(int j=1;j<=t;j++){
			int l=p[j],r=nxt[l],R=i;
			if(pre[i][j]==r-l+1)continue;
			for(int z=min(r-l,R-1)-1;z>=0;z--){
				bool flag=1;
				for(int k=0;k<26;k++)
					if(ss[r][k]-ss[l-1][k]<st[R][k]-st[R-z-1][k])
						{flag=0;break;}
				if(flag){f[i+1][j+1]=z+1;ans=max(ans,z+1);break;}
			}
		}
	for(int i=1;i<=m;i++)
		for(int j=1;j<=t;j++){
			int l=p[j],r=nxt[l];
			if(pre[i][j]==r-l+1){
				f[i+r-l+1][j+1]=f[i][j]+r-l+1;
				ans=max(ans,f[i][j]+r-l+1);
			}
			ans=max(ans,f[i][j]+pre[i][j]);
		}
	printf("%d\n",ans);
	return 0;
}

标签:node,P4983,bar,leq,int,wqs,斜率,bool,include
来源: https://www.cnblogs.com/QuantAsk/p/15004762.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有