題意
給定長度為N的包含0,1,2的a序列,和一個長度為N的包含字元M,E,X的字串s。對於所以符合條件的1<=i<j<k<=N,使得s[i]s[j]s[k]=="MEX"的三元組(i,j,k),請你求出所有mex(a[i],a[j],a[k])之和。mex()函式表示未出現在序列中的最小非負整數。
思路
我們先看一個非常典的題目,給你一串由a,b,c構成的字串,請問裡面能構成"abc"的子序列有多少組。這個題的思路就可以沿用於此題,我們維護一個a出現次數的字首和,和一個c出現次數的字尾和,如果一旦遇到b這個字元,根據乘法原理,我們就用a的字首和乘以c的字尾和,然後加到ans上去,就可以O(n)解決此題。同理,對於這個題,我們對於每個M與X,前者開三個字首和、後者三個字尾和,表示字元為M,對應的數字是0,1,2;字元為X,對應的數字是0,1,2。然後O(n)遍歷,一旦遇到了E,那麼我們就對於9種情況全部操作一遍,然後算出貢獻即可。
程式碼
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+10;
int a[maxn];
int s[maxn];
int m[maxn][5];
int x[maxn][5];
signed main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
string sss;
cin>>sss;
for(int i=1;i<=n;i++)
{
char flag=sss[i-1];
if(flag=='M') s[i]=0;
if(flag=='E') s[i]=1;
if(flag=='X') s[i]=2;
}
for(int i=1;i<=n;i++)
{
m[i][0]=m[i-1][0];
m[i][1]=m[i-1][1];
m[i][2]=m[i-1][2];
if(s[i]==0) m[i][a[i]]++;
}
for(int i=n;i>=1;i--)
{
x[i][0]=x[i+1][0];
x[i][1]=x[i+1][1];
x[i][2]=x[i+1][2];
if(s[i]==2) x[i][a[i]]++;
}
int ans=0;
for(int i=1;i<=n;i++)
{
if(s[i]==1)
{
for(int j=0;j<=2;j++)
{
for(int k=0;k<=2;k++)
{
int t=0;
for(t=0;t<=3;t++)
if(t!=a[i]&&t!=j&&t!=k) break;
ans+=t*m[i][j]*x[i][k];
}
}
}
}
cout<<ans<<endl;
return 0;
}