1. 程式人生 > 其它 >CF173A Rock-Paper-Scissors 題解

CF173A Rock-Paper-Scissors 題解

CF173A Rock-Paper-Scissors 題解

Content

\(2\) 個人在玩石頭剪刀布,已知他們的出手都有一定的規律,求 \(n\) 局之後兩個人各輸了幾局。

資料範圍:\(1\leqslant n\leqslant 2\times 10^9\),週期長度不超過 \(10^3\)

Solution

一個一個模擬肯定不現實,會 TLE,所以我們應當考慮是否有更快速的方法。

我們設第一個人的週期長度為 \(a_1\),第二個人的週期長度為 \(a_2\),則很容易發現,在 每 \(\operatorname{lcm}(a_1,a_2)\) 局裡面,他們輸的局數是固定的,因為他們正好能夠做完整數個週期,而且可以證明 \(\operatorname{lcm}(a_1,a_2)<10^6\)

,所以我們考慮將一個週期裡面每局的情況都統計出來,如果能湊出 \(\operatorname{lcm}(a_1,a_2)\) 局出來,就計算有多少個 \(\operatorname{lcm}(a_1,a_2)\) 局,顯然有 \(\left\lfloor\dfrac{n}{\operatorname{lcm}(a_1,a_2)}\right\rfloor\) 個,直接拿兩個人在每 \(\operatorname{lcm}(a_1,a_2)\) 局裡面輸的次數乘上 \(\left\lfloor\dfrac{n}{\operatorname{lcm}(a_1,a_2)}\right\rfloor\)
,再加上他們剩下來的幾局中的輸的次數即可。

Code

string s1, s2;
int n, loses[1000007], loset[1000007], lose1, lose2, ans1, ans2;

inline int gcd(int a, int b) {return !b ? a : gcd(b, a % b);}
inline int lcm(int a, int b) {return a / gcd(a, b) * b;} //NOIP2020T1 血的教訓

int main() {
	n = Rint; str(s1, len1); str(s2, len2);
	int round = lcm(len1, len2);
	F(i, 0, round - 1) {
		if((s1[i % len1] == 'R' && s2[i % len2] == 'P') || (s1[i % len1] == 'P' && s2[i % len2] == 'S') || (s1[i % len1] == 'S' && s2[i % len2] == 'R'))
			loses[i + 1]++, lose1++;
		if((s2[i % len2] == 'R' && s1[i % len1] == 'P') || (s2[i % len2] == 'P' && s1[i % len1] == 'S') || (s2[i % len2] == 'S' && s1[i % len1] == 'R'))
			loset[i + 1]++, lose2++;
	}
	F(i, 1, n % round) ans1 += loses[i], ans2 += loset[i];
	return printf("%d %d", ans1 + lose1 * (n / round), ans2 + lose2 * (n / round)), 0;
}