[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)。