CF1766E
cats142857 · · 题解
给定一个长为
由于
不考虑
考虑枚举区间的左端点,对其右侧的所有右端点计算贡献和。对于每个左端点,在其向右添加元素时,只要遇到非
当第一个数组的尾部为
每个左端点
-
如果
nval[i] 不为-1 ,设t=nval[i] ,则从t 位置开始,第一个数组就会出现,对答案加上相应的贡献。否则这个左端点对答案的贡献为0 ,并跳过下面的步骤。 -
如果
a[t]=2 ,且n1[t] 不为-1 ,则从n1[t] 位置开始,纯1 数组就会出现,对答案加上相应的贡献。否则,如果n31[t] 不为-1 ,则从n31[t] 位置开始,纯1 数组就会出现,对答案加上相应的贡献。如果两个条件都不满足,则纯1 数组不会出现。 -
纯
2 数组同理。
总时间复杂度为
#include <bits/stdc++.h>
using namespace std;
int a[300000],nval[300000],n1[300000],n2[300000],n31[300000],n32[300000];
int main(int argc, char** argv) {
ios::sync_with_stdio(false),cin.tie(0);
long long ans=0,n,i,t;
cin>>n;
for(i=0;i<n;i++)
{
cin>>a[i];
if(a[i]==0)ans+=(long long)(i+1)*(n-i);
}
for(i=n-1;i>-1;i--)
{
if(a[i]>0)nval[i]=i;
else
{
if(i==n-1)nval[i]=-1;
else nval[i]=nval[i+1];
}
}
for(i=n-1;i>-1;i--)
{
if(a[i]==1)n1[i]=i;
else if(a[i]==0||a[i]==2)
{
if(i==n-1)n1[i]=-1;
else n1[i]=n1[i+1];
}
else n1[i]=-1;
}
for(i=n-1;i>-1;i--)
{
if(a[i]==2)n2[i]=i;
else if(a[i]==0||a[i]==1)
{
if(i==n-1)n2[i]=-1;
else n2[i]=n2[i+1];
}
else n2[i]=-1;
}
for(i=n-1;i>-1;i--)
{
if(i<n-1&&a[i]==3&&nval[i+1]!=-1&&a[nval[i+1]]==2&&n1[nval[i+1]]!=-1)n31[i]=n1[nval[i+1]];
else if(i==n-1)n31[i]=-1;
else n31[i]=n31[i+1];
}
for(i=n-1;i>-1;i--)
{
if(i<n-1&&a[i]==3&&nval[i+1]!=-1&&a[nval[i+1]]==1&&n2[nval[i+1]]!=-1)n32[i]=n2[nval[i+1]];
else if(i==n-1)n32[i]=-1;
else n32[i]=n32[i+1];
}
for(i=0;i<n;i++)
{
t=nval[i];
if(t==-1)continue;
ans+=n-t;
if(a[t]==1&&n2[t]!=-1)ans+=n-n2[t];
else if(n32[t]!=-1)ans+=n-n32[t];
if(a[t]==2&&n1[t]!=-1)ans+=n-n1[t];
else if(n31[t]!=-1)ans+=n-n31[t];
}
cout<<ans<<'\n';
return 0;
}