CF 718 E - Group Photo

给出一个ai数组,然后构造C和P序列,两个序列的合集是1到n的排列。然后c的排列对应的a的和要小于p对应的a的和。

而且C序列相隔两个数的差值要递增,P要递减。 具体还是去看题目吧(少写点字)

 

由于C要递增,P要递减,因此只有几种情况

1.C一开始是连续的,然后后面是差值为2。 (12345 7 9 11 。。。。)

2.C前面放一个P,然后从2开始的第一种情况

3.整个CP序列最后是C,然后前面按第一种情况

4.2,3整合

还有特殊的两种

5. CP序列C都在最后面。

6. 没有C

 

 

对于前4种,枚举c连续到那个位置,然后二分后面差值为2的下标最远可以去到哪里,然后就加加减减判断下前面有没有多的p后面有没有多的c就好了。

由于枚举的时候,2,3会和第一种有重复 (CPC结尾),因此2,3在做二分的时候,最右只能去到n-3(n-2就会出现重复了). (就是这里写错了导致没A到啊。。上分失败T_T)

对于第5种,就直接枚举后面有多少个C了

第6种直接加1就好了。

 

 

using namespace std;
int mod = 998244353;
//int mod = 1e9+7;

int n,m;

ll sum[N],qs[N];
ll a[N];


int sol(int idx, int n, ll tot, ll es, ll ecs){
	ll cur_sum = sum[idx]-es + ecs;
	int l = idx, r = n+1;
	while(l+4<r){
		int mid = (l+r)>>1;
		int p_mid = mid;
		if((mid - idx)%2){
			p_mid--;
		}
		ll s = qs[p_mid] - qs[idx];
		s += cur_sum;
		ll ss = tot - s;
		if(s<ss){
			l = p_mid;
		}
		else {
			r = p_mid;
		}
	}
	int ret = l-1;
	for(int i = l; i <=min(n,r); i+=2){
		ll s = qs[i] - qs[idx];
		s += cur_sum;
		ll ss = tot - s;
		if(s<ss){
			ret = i;
		}
	}
	if(ret<l){
		return 0;
	}
	return (ret + 2 - idx)/2;
}

int main(){

	int t;
	cin>>t;
	while(t--){
		sf("%d",&n);
		fr(i,1,n+1){
			sf("%lld",&a[i]);
			sum[i] = sum[i-1]+a[i];
		}
		fr(i,1,n+1){
			if(i==1) qs[i] = a[i];
			else qs[i] = qs[i-2] + a[i];
		}
		ll ans = 0;
		for(int i = 1; i <=n; ++i){
			ans = (ans + sol(i,n,sum[n],0,0))%mod;
			if(i>1){
				ans = (ans + sol(i,n,sum[n],sum[1],0))%mod;
			}
			if(i<n){
				ans = (ans + sol(i,n-3,sum[n],0,a[n]))%mod;
			}
			if(i>1&&i<n){
				ans = (ans + sol(i,n-3,sum[n],a[1],a[n]))%mod;
			}
		}
		for(int i = 3; i <=n; ++i){
			ll s1 = sum[i-1];
			ll s2 = sum[n]- s1;
			if(s2<s1){
				ans = (ans + 1 ) %mod;
			}
		}
		cout<<ans+1<<endl;
	}
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值