Atcoder Grand Contest 033

033E Go around a Circle

题目描述

点此看题

解法

如果 \(S_1=B\),我们可以翻转整个 \(S\),那么可以让 \(S_1=R\) 并且答案不变。

那么开始写必要条件,你一定要利用好 满足将棋子放在任意一个点上,都存在方案 这个限制。首先我们可以知道环上不存在相邻的两个 B,因为起点放在 B 之间就会不合法。

我们可以特判掉 \(S\) 全是 R 的情况,那么现在的 \(S\) 就是 R/B 分段间隔出现,设这些段是 \(c_{1,2...k}\)

我们发现环上每段 R 都必须是奇数,因为如果是偶数,那么无论 \(c_1\) 是奇数或者偶数,我们都可以通过设置起点,使得走完 \(c_1\) 之后还卡在 R 段的中间。

此外 \(c_1\) 的要求还没有考虑完,如果 \(c_1\) 是奇数,那么要求每一段的 R 不超过 \(c_1\),因为如果长度超过 \(c_1\),放置在一段无法走到另一端;如果 \(c_1\) 是偶数,那么要求每一段 R 的长度不超过 \(c_1+1\),类似地我们放置在一段的下一个点无法走到另一端。

对于 \(S\) 中其他的 R 段,起点一定是环上 R 的一段,所以如果对应的 \(c_i\) 是奇数,那么只能从一段走到另一端,所以要求每一段的长度都不能超过 \(c_i\);如果对应的 \(c_i\) 是偶数,只会在端点反复横跳,所以没有限制。总结一下就是对于 \(i\in[2,k)\)(最后一段没有限制),如果 \(i\)\(c_i\) 都是奇数,那么长度不超过 \(c_i\)

有了上面的必要条件之后充分性不难说明。


那么现在的限制转化为:求环的方案数,要求不能有相邻的 B,并且 R 的连续段不能超过某个定值。

直接一维 \(dp\),设 \(f_i\) 表示前 \(i\) 个点分段(一段的 RB 一起考虑)的方案数,注意我们只对偶数位进行 \(dp\),可以用前缀和优化。最后算答案的时候考虑翻转,如果最后一段长度为 \(i\) 就有 \(i\) 种翻转方案:

\[ans=\sum f_{n-i}\cdot i \]

时间复杂度 \(O(n)\)

#include <cstdio>
#include <iostream>
using namespace std;
const int M = 200005;
#define int long long
const int MOD = 1e9+7;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,k,w,ans,c[M],dp[M][2][2],g[M],f[M];char s[M];
void work()
{
	dp[1][0][0]=dp[1][1][1]=1;
	for(int i=2;i<=n;i++)
	{
		dp[i][0][0]=(dp[i-1][0][0]+dp[i-1][0][1])%MOD;
		dp[i][0][1]=dp[i-1][0][0];
		dp[i][1][0]=(dp[i-1][1][0]+dp[i-1][1][1])%MOD;
		dp[i][1][1]=dp[i-1][1][0];
	}
	ans=(dp[n][0][0]+dp[n][0][1]+dp[n][1][0])%MOD;
	printf("%lld\n",ans);
}
signed main()
{
	n=read();m=read();scanf("%s",s+1);
	for(int i=1,j=1;i<=m;i=j)
	{
		j=i;while(j<=m && s[i]==s[j]) j++;
		c[++k]=j-i;
	}
	if(k==1) {work();return 0;}
	if(n&1) {puts("0");return 0;}
	w=c[1]+!(c[1]&1);
	for(int i=3;i<k;i+=2)
		if(c[i]&1) w=min(w,c[i]);
	f[0]=g[0]=1;
	for(int i=2;i<=n;i+=2)
	{
		f[i]=(g[i-2]+(i-w-3>=0?MOD-g[i-w-3]:0))%MOD;
		g[i]=(g[i-2]+f[i])%MOD;
	}
	for(int i=2;i<=min(n,w+1);i+=2)
		ans=(ans+f[n-i]*i)%MOD;
	printf("%lld\n",ans);
}
posted @ 2022-03-24 20:49  C202044zxy  阅读(49)  评论(0编辑  收藏  举报