[ARC169E] Avoid Boring Matches

发布时间 2023-12-12 12:40:15作者: 灰鲭鲨

题解链接

非常厉害的一道题。

考虑无解是什么情况? R 的个数超过 \(2^{n-1}\)

先考虑如何判定。从前往后考虑,如果遇到一个 B,那么如果后面有 R,就选最靠前的 R,否则选最靠后的一个 B.如果遇到 R,就选最靠后的一个 B

但是这个判定很繁琐。我们考虑求出一个合法序列,使得他的 B 尽量靠后。设长度为 \(2^i\)B 尽量靠后的串为 \(t_i\),那么 \(t_0=\)R,考虑从 \(t_{i-1}\) 扩展到 \(t_i\).

遍历 \(t_{i-1}\),那么遇到一个 R 的时候,他匹配的是最远的 B,\(t_i\) 增加 R。遇到一个 B 的时候,他匹配最近的 R,所以增加 BR,剩下的用 B 补全即可。

然后有一个结论.考虑原串中前 \(2^{n-1}\) 个,设第 \(i\)B\(g_i\) 出, \(t_n\)\(i\)B\(h_i\) 处。当且仅当 \(\forall i,g_i\le h_i\),串合法。

感性理解一下,如果原串有个 B\(t_n\)B 的后面,那么他就匹配不到 R
所以最终答案就是原串的 B\(t_n\)B 的位置差加起来就行了。

// LUOGU_RID: 139274680
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int n,m,k,g[N],c;
long long ans; 
char s[N],t[19][N];
int main()
{
	scanf("%d%s",&n,s+1);
	for(int i=1;s[i];i++)
		if(s[i]=='R')
			++c;
	if(c>(1<<n-1))
		return puts("-1"),0;
	t[0][1]='R';
	for(int i=1;i<=n;i++)
	{
		m=0;
		for(int j=1;j<=(1<<i-1);j++)
		{
			if(t[i-1][j]=='B')
				t[i][++m]='B',t[i][++m]='R';
			else 
				t[i][++m]='R';
		}
		while(m<(1<<i))
			t[i][++m]='B';
	}
	m=0;
	for(int i=1;i<=(1<<n);i++)
		if(t[n][i]=='B')
			g[++m]=i;
	for(int i=1;i<=(1<<n);i++)
	{
		if(s[i]=='B')
		{
			++k;
			if(k>m)
				break;
			ans+=max(i-g[k],0);
		}
	}
	printf("%lld",ans);
}