AT_arc175_a [ARC175A] Spoon Taking Problem 題解

whrwlx發表於2024-03-25

題目翻譯 link

\(N\) 人圍坐在一張圓桌旁,按逆時針順序編號為 \(1\)\(N\) 。每個人都有一個慣用手

圓桌上有 \(N\) 把勺子,編號為 \(1\)\(N\) ,每對相鄰的人之間放一把勺子

給你一個 \((1, \dots, N)\) 的排列組合 \((P_1, \dots, P_N)\) 。在 \(i=1,\dots,N\) 的順序中,人 \(P_i\) 的行為如下:

  • 如果兩邊都有剩餘的勺子,他們會拿自己慣用手一邊的勺子
    • 如果左側或右側有剩餘的勺子,他們將拿走其中一個
  • 否則,他們什麼也不會做

給出了一個長度為 \(N\) 的字串 \(S\) ,由 LR?組成:

  • 如果 \(S_i\) 是 "L",那麼 \(i\) 是左撇子
  • 如果 \(S_i\) 是 "R",那麼 \(i\) 是右撇子

\(2^N\) 個可能的主手組合中,找出有多少個滿足以下所有條件的 \(s\),模數為 \(998244353\)

當每個人都行動完後,每個人都拿了一把勺子

方法

法一

暴力列舉每種可能的 \(s\) ,然後檢驗

時間複雜度 \(O_{(2^X \times N)}\)\(X\)? 的個數

法二

分析

我們可以發現對於一個滿足條件的 \(S\) ,每個人都應該拿與第一個拿的人同側的勺子

於是:

我們可以分類討論

討論第一個拿的人是拿左邊還是右邊:

  • 若為 R 只討論右邊
  • L 只討論左邊
  • ? 討論兩種最後求和

每個人拿的方向應與第一個拿的人一致,然後找規律

規律

(注:這裡類似 “ \(P_i\)L ” 的語句其實是 “ \(S[P_i]\)L ” ,為了簡便記作 \(P_i\)

若第一個拿的人拿左邊

對於第 \(P_i\) 個人來說

  • 如果他右邊的人 \(r\) 已經先拿過他左邊的勺子,那麼 \(P_i\) 可以為 LR ,那麼 \(ans\)\(2\) (注意,若 \(P_i\) 確定, \(ans\) 不變)
  • 如果他右邊的人 \(r\) 後拿,那麼他只能拿左邊的勺子, \(ans\) 不變
  • 如果他右邊的人 \(r\) 沒有先拿過他左邊的勺子且 \(P_i=\) R ,那麼第一個拿的人拿左邊的情況誤解,即 \(ans=0\)

若第一個拿的人拿右邊,可類似若第一個拿的人拿左邊推出

這裡為了簡短就不寫啦

注意取模!!!你猜我怎麼知道的 警示後人

程式碼實現:

#include<bits/stdc++.h>
#define put(n) scanf("%lld",&n) 
#define out(n) printf("%lld\n",n)
#define int long long
#define fd(i,a,b) for(int i=a;i<=b;i=-~i)
using namespace std;
int n,p[1000100],f[1000100],mod=998244353;
//f記錄第i個人第幾個拿
char s[1000100];
int ans1=1,ans2=1;// 拿左邊 拿右邊
signed main()
{
	put(n);
	fd(i,1,n) put(p[i]),f[p[i]]=i;
	fd(i,1,n) cin>>s[i];
	//第一個拿的人拿左邊
	fd(i,1,n)
	{
		int r=p[i]+1;//r 當前拿的人右邊的人的編號
		if(r==n+1) r=1;//小坑
		if(s[p[i]]=='?')
		{
			if(f[r]<i) ans1*=2;
			ans1%=mod;
		}
		else if(s[p[i]]=='R')
		{
			if(f[r]>i)
			{
				i=n+1;
				ans1=0;
				break;
			}
		}
	}
	//第一個拿的人拿右邊
	fd(i,1,n)
	{
		int l=p[i]-1;//l 當前拿的人左邊的人的編號
		if(l==0) l=n;//小坑
		if(s[p[i]]=='?')
		{
			if(f[l]<i) ans2*=2;
			ans2%=mod;
		}
		else if(s[p[i]]=='L')
		{
			if(f[l]>i)
			{
				i=n+1;
				ans2=0;
				break;
			}
		}
	}
	if(s[p[1]]=='R') out(ans2);
	else if(s[p[1]]=='L') out(ans1);
	else out((ans1+ans2)%mod);//如果Pi為?那麼算兩種情況之和
	return 0;
}

無關的話(稽核大大,求過審):被禁言了,怎麼解啊?

感謝觀看

相關文章