「杂题乱刷2」CF1738E Balance Addicts
题目链接
解题思路
发现我们可以直接枚举左端点 \(L\),那么此时显然右端点 \(R\) 的取值范围也随之确定,那么此时 \(L\) 能往右移当且仅当 \(L + 1<R\) 与 \(a_{L+1} = 0\),\(R\) 能往左移当且仅当 \(L<R - 1\) 与 \(a_{R-1} = 0\)。
那么 \(L,R\) 的取值范围确定后,此时会有以下两种情况:
-
\(L,R\) 的取值范围不相交,此时显然枚举分的段数 \(k\) 然后两端组合数部分相乘即可。
-
\(L,R\) 的取值部分相交,此时直接让两个取值范围一定,然后枚举分的段数 \(k\),此时显然 \(k\) 为偶数,依然组合数计算即可。
由于双指针,时间复杂度 \(O(n)\)。
参考代码
ll n;
ll a[1000010];
ll L,R;
ll pre[1000010],suf[1000010];
ll ans;
ll l,r;
void solve()
{
ans=1;
cin>>n;
forl(i,1,n)
cin>>a[i];
forl(i,1,n)
pre[i]=pre[i-1]+a[i];
suf[n+1]=0;
forr(i,n,1)
suf[i]=suf[i+1]+a[i];
R=n;
forL(L,1,n,L<R)
{
while(L<R-1 && suf[R]<pre[L])
R--;
if(pre[L]==suf[R])
{
l=L,r=R;
while(L<R-1 && suf[R-1]==pre[L])
R--;
while(L+1<R && suf[R]==pre[L+1])
L++;
ll S=0;
if(L==R-1 && pre[L]==suf[L+1])
{
forll(k,0,r-l+1,2)
S=(S+C(r-l+1,k))%mod;
ans=(ans*S)%mod;
continue;
}
forl(k,0,min(L-l+1,r-R+1))
S=(S+C(L-l+1,k)*C(r-R+1,k)%mod)%mod;
ans=(ans*S)%mod;
}
}
cout<<ans<<endl;
}

浙公网安备 33010602011771号