codeforces1428F Fruit Sequences

https://codeforces.com/contest/1428/problem/F

vp的时候没想出来。。。主要D想太久了,其实F也不太会

这题的关键是想到对于一个确定的r,l越左高度f(l,r)越高

于是就能想到每次r向右拓展一格,如果是1个新的1,那么左边就有一部分要全增加1

于是一个很简单想法就是在线段树上二分找到覆盖到哪里,然后区间覆盖,然后求个前缀和就是这个当前r对应的所有f(l,r)之和

然而这样十分难写

于是我们发现每次增加只增加1,且我们可以考虑对当前末尾最长的连续的1,[l,r],这一段是全部要+1的,然后l左边的就尝试用r-l+1去覆盖他们,我们就可以用rid[i]表示高度为i的最右边的端点在哪,每次r新增一个1,就把rid[r-l+1]=l,然更新一下总和就行了,[l+1,r]这一段是一个等差数列可以直接算,当s[r+1]='0'时,再更新一下rid[1]-rid[r-l+1]

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxl=5e5+10;

int n,m,cnt,tot,cas;ll ans;
int a[maxl];ll rid[maxl];
bool vis[maxl];
char s[maxl];

inline void prework()
{
	scanf("%d",&n);
	scanf("%s",s+1);
}

inline void mainwork()
{
	ll tmp=0,l=1,r;ans=0;
	for(int i=1;i<=n;i++)
	if(s[i]=='0')
		ans+=tmp,l=i+1,rid[0]=i;
	else
	{
		r=i;
		tmp-=(rid[r-l]-rid[r-l+1])*(r-l);
		tmp+=(l-rid[r-l+1])*(r-l+1);
		rid[r-l+1]=l;
		tmp+=r-l;
		ans+=tmp;	
		if(s[i+1]!='1' && i+1<=n)
		{
			for(int j=1;j<=r-l;j++)
				rid[j]=r-j+1;
		}
	}
}

inline void print()
{
	printf("%lld",ans);
}

int main()
{
	int t=1;
	//scanf("%d",&t);
	for(cas=1;cas<=t;cas++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/109210783