[CF1517E]Group Photo

Group Photo

题解

很容易发现,一个符合条件的序列大概长下面两种样子:
P . . . P C . . . C P...PC...C P...PC...C
( P ) C . . . C P C P C . . . P C P . . . P ( C ) (P)C...CPCPC...PCP...P(C) (P)C...CPCPC...PCP...P(C)
第一个就是一段连续的P加一段连续的C,符合这个条件的序列可以通过枚举得到。
第二个是两端可能有一个 P / C P/C P/C,中间外侧是连续的 P P P与连续的 C C C,最中间是接连不断的 P C PC PC
我们可以根据两端有无 P / C P/C P/C分4种情况讨论,对于每种情况,先枚举连续的 C C C,再二分能够有多少段 P C PC PC,二分时根据前缀和判断和是否超过了一半。

总时间复杂度 O ( t n l o g   n ) O\left(tnlog\,n\right) O(tnlogn)

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define lowbit(x) (x&-x)
#define reg register
typedef long long LL;
typedef unsigned long long uLL;
typedef unsigned int uint;
typedef pair<int,int> pii;
const LL INF=0x7f7f7f7f7f7f;
const int mo=998244353;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
int t,n;
LL a[MAXN],sum[MAXN],num[MAXN];
int add(int x,int y){return x+y<mo?x+y:x+y-mo;}
signed main(){
	read(t);
	while(t--){
		read(n);for(int i=1;i<=n;i++)read(a[i]);int ans=0;
		for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
		num[1]=a[1];for(int i=2;i<=n;i++)num[i]=num[i-2]+a[i];
		for(int i=2;i<n-1;i++)if(2ll*sum[i]>sum[n])ans=add(ans,1);
		for(int i=0;i<=n;i++){
			int l=0,r=(n-i)/2;
			if(2ll*sum[i]>=sum[n]||l>r)continue;
			while(l<r){
				int mid=l+r+1>>1;
				if(2ll*(sum[i]+num[i+2*mid]-num[i])<sum[n])l=mid;
				else r=mid-1;
			}
			ans=add(ans,l+1);//printf("1st %d:%d\n",i,l+1);
		}
		for(int i=3;i<=n;i++){
			int l=0,r=(n-i)/2;
			if(2ll*(sum[i]-a[1])>=sum[n]||l>r)continue;
			while(l<r){
				int mid=l+r+1>>1;
				if(2ll*(sum[i]+num[i+2*mid]-num[i]-a[1])<sum[n])l=mid;
				else r=mid-1;
			}
			ans=add(ans,l+1);//printf("2nd %d:%d\n",i,l+1);
		}
		for(int i=0;i<n;i++){
			int l=0,r=(n-i-1)/2-1;
			if(2ll*(sum[i]+a[n])>=sum[n]||l>r)continue;
			while(l<r){
				int mid=l+r+1>>1;
				if(2ll*(sum[i]+num[i+2*mid]-num[i]+a[n])<sum[n])l=mid;
				else r=mid-1;
			}
			ans=add(ans,l+1);//printf("3rd %d:%d\n",i,l+1);
		}
		for(int i=3;i<n-1;i++){
			int l=0,r=(n-i-1)/2-1;
			if(2ll*(sum[i]+a[n]-a[1])>=sum[n]||l>r)continue;
			while(l<r){
				int mid=l+r+1>>1;
				if(2ll*(sum[i]+num[i+2*mid]-num[i]+a[n]-a[1])<sum[n])l=mid;
				else r=mid-1;
			}
			ans=add(ans,l+1);//printf("4th %d:%d\n",i,l+1);
		}
		printf("%d\n",ans);
	}
	return 0;
}

谢谢!!!

posted @ 2021-04-24 17:38  StaroForgin  阅读(11)  评论(0)    收藏  举报  来源