给出一个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;
}
}