[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;
}

浙公网安备 33010602011771号