[ARC175A] Spoon Taking Problem

[ARC175A] Spoon Taking Problem

Atcoder problems 评分: 1132 \color{SeaGreen}{1132} 1132

赛时切掉,忘取模罚时一发,恼。

其实这道题是个诈骗题。仔细读题可以发现这 n n n 个人或是都取左边的勺子,或是都取右边的勺子。如果一个人取左边且有另一个人取右边,那么最后一定有一个人取不到勺子。

如果想明白了上面的道理,题也就不难写了。

考虑都选左边的和都选右边的两种情况,最后把方案数累加即可。

考虑都选左边的情况:

  • 当前人的惯用手是左手,则判断他左边的勺子是否被取走。如果被取走,则不存在都选左边的情况,退出循环;如果没有被取走,将左边的勺子标记为被取走。

  • 当前人的惯用手是右手,则判断他右边的勺子是否被取走。如果没有被取走,则不存在都选左边的情况,退出循环;如果被取走,将左边的勺子标记为被取走。

  • 当前人的惯用手不确定。则判断他左边的勺子是否被取走。如果被取走,则不存在都选左边的情况,退出循环;如果左边勺子没有被取走,再判断右边的勺子是否被取走,如果右边勺子被取走,则将左边的勺子标记为被取走,答案乘 2 2 2(因为惯用手有两种选法),否则将左边的勺子标记为被取走。

一些细节:

  • i i i 个人左边的勺子编号为 i i i,右边的勺子编号为 i   m o d   n + 1 i \bmod n + 1 imodn+1
  • 记得对 998244353 998244353 998244353 取模。

完整代码:

#include<bits/stdc++.h>
#define LL long long
#define mod 998244353
using namespace std;
const int N=2e5+10;
int n,p[N];
bool vis[N];
char s[N];
int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0); cout.tie(0);
	scanf("%d",&n);
	for(int i=1;i<=n;i++) vis[i]=1;
	for(int i=1;i<=n;i++) scanf("%d",&p[i]);
	scanf("%s",s+1);
	//都用左手
	bool flag=0;
	LL ans1=1,ans2=1;
	for(int i=1;i<=n;i++)
	{
		if(s[p[i]]=='R')
		{
			if(vis[p[i]%n+1]){flag=1;break;}
			else vis[p[i]]=0;
		}
		else if(s[p[i]]=='L')
		{
			if(!vis[p[i]]){flag=1;break;}
			else vis[p[i]]=0;
		}
		else
		{
			if(vis[p[i]]&&vis[p[i]%n+1]) vis[p[i]]=0;
			else if(vis[p[i]]) vis[p[i]]=0,ans1=(ans1<<1)%mod;
			else {flag=1;break;}
		}
	}
	if(flag) ans1=0;
	flag=0;
	for(int i=1;i<=n;i++) vis[i]=1;
	//都用右手
	for(int i=1;i<=n;i++)
	{
		if(s[p[i]]=='L')
		{
			if(vis[p[i]]){flag=1;break;}
			else vis[p[i]%n+1]=0;
		}
		else if(s[p[i]]=='R')
		{
			if(!vis[p[i]%n+1]){flag=1;break;}
			else vis[p[i]%n+1]=0;
		}
		else
		{
			if(vis[p[i]]&&vis[p[i]%n+1]) vis[p[i]%n+1]=0;
			else if(vis[p[i]%n+1]) vis[p[i]%n+1]=0,ans2=(ans2<<1)%mod;
			else {flag=1;break;}
		}
	}
	if(flag) ans2=0;
	printf("%lld",(ans1+ans2)%mod);
	return 0;
}

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

  • 55
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值