ABC 308E MEX

Linear_L發表於2024-06-03

題意
給定長度為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;
 }