Atcoder Grand Contest 033

033E Go around a Circle

题目描述

点此看题

解法

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

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

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

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

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

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

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


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

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

ans=fnii

时间复杂度 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 @   C202044zxy  阅读(50)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
历史上的今天:
2021-03-24 [正睿集训2021] 计算几何
点击右上角即可分享
微信分享提示