「ABC242D」ABC Transform 題解
阿新 • • 發佈:2022-03-06
我果然還是太cai了
題目簡介
給定一個長度為 \(N\) 的字串 \(S\) ,由A
B
C
三種字元組成,每一次變化會使 \(S\) 中的 A
全部變成 BC
,B
全部變成 CA
,C
全部變成 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 **