1. 程式人生 > 其它 >「ABC242D」ABC Transform 題解

「ABC242D」ABC Transform 題解

我果然還是太cai了

題目簡介

傳送門

給定一個長度為 \(N\) 的字串 \(S\) ,由A B C 三種字元組成,每一次變化會使 \(S\) 中的 A 全部變成 BCB 全部變成 CAC 全部變成 AB ,如 ABC 在一次變化後會變成 BCCAAB 。現在有 Q 個詢問,每個詢問都是求原串 \(S\) 經過 \(t_i\) 次變化後第 \(k_i\) 個字元。

分析

越來越菜了,首次接觸 \(D\) 題連一點思路都沒有。

\(f(t,k)\) 為原串 \(S\) 經過 \(t_i\) 次變化後第 \(k_i\) 個字元。

首先,當 \(t=0\) 時 ,輸出 \(S_k\)

就行了。

其次,當 \(t\neq 0\) 時,我們得清楚 \(f (t,k)\) 是從哪兒來的。

試看樣例

ABC ->
BCCAAB ->
CAABABBCBCCA

採用分類討論的方法,不難發現

  • \(k\in \{2m+1|m\in \mbox{Z}\}\) ( 即 \(k\) 為奇數 ) 時,\(f(t,k)\) 來自 \(f(t-1,\frac{k+1}{2})\)
  • \(k\in \{2m|m\in \mbox{Z}\}\) ( 即 \(k\) 為偶數 ) 時,\(f(t,k)\) 來自 \(f(t-1,\frac{k}{2})\)

怎麼進行變化?

可以概闊為一個 \(g\)

函式:

inline char g(char ch,int x){
	return (ch-'A'+x)%3+'A';
}

但是,如果我們每一次都去遞迴 \(t\) 次,看一眼 \(t\leq 10^{18}\),肯定會爆的。

\(k\) 下手。

觀察上面樣例中的字串首,會發現它們是 A B C輪換。

可以利用這條性質,當 \(k=0\) 時,直接求取 \(f(t,0)=g(S.front(),t\ \mbox{mod}\ 3)\)

但是問題來了,這樣一個演算法肯定會對 \(k\) 取模,那麼萬一 \(k=0\dots\)

所以,我們將 \(S\) 改為從 \(0\)\(N-1\) 編號。

此時:

  • \(k\in \{2m+1|m\in \mbox{Z}\}\) 時,\(f(t,k)\) 來自 \(f(t-1,\frac{k-1}{2})\)
  • \(k\in \{2m|m\in \mbox{Z}\}\) 時,\(f(t,k)\) 來自 \(f(t-1,\frac{k}{2})\)

程式碼就非常好寫了:

\(AC\ Code\)

#include<cstdio>
#include<string>
#include<iostream>
using namespace std;
inline char g(char ch,int x){
	return (ch-'A'+x)%3+'A';
}
typedef long long ll;
string s;
char f(ll t,ll k){
	if(!t)return s[k];
	if(!k)return g(s[0],t%3);
	return g(f(t-1,k>>1),(k&1)+1);
}
int main(){
	int q;
	cin>>s>>q;
	while(q--){
		ll t,k;
		cin>>t>>k;
		cout<<f(t,k-1)<<'\n';
	}
	return 0;
} 

再說一遍,我是 **XX **

$$-----EOF-----$$