给一个字符串,现有这么一种操作,将字符串内每一个字母替换成一给定字符串。例如Ta=abc,Tb=ee,那么ab就会被替换成abcee。
给出初始的字符串S,和26个字母所对应的字符串Ti,应用操作K次,询问第i个位置的字符。
∣S∣≤1000000
2≤∣Ti∣≤50,K≤1015
分析
头秃。开始以为关键是在于数出一个字符串经过K次操作后达到的长度,然后然后用类似于二分的方法去递归地分层找到需要的位置。于是就统计每个字母的数目,用矩阵快速幂拿到长度……
现在看着过于智障。这1e15的指数和1e15的下标,你怎么敢快速幂。
由替换字符串的长度可以得到,这种操作顶多执行50次(250)。因此字符串的长度部分计算实际上不占大头,用个倍增就能处理出来。
现在剩下的问题是操作次数K过大。方法仍然是基于50次。一个字符扩展50次,就足够把所有的询问包含在内。因此要计算出第一个字符替换的循环节,将操作次数降到接近50。此后通过倍增法去一层层定位询问下标所处的位置。
最开始方向错了是一码事…感觉K的范围也挺无聊的…代码等到之后再补上。
代码
实际实现时,降K可能浮动26左右,所以多处理这么一点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| #include <vector> #include <algorithm> #include <iostream> #include <stack> #include <cstring> #include <cassert> using namespace std; using ll=long long; const int MAXN=30;
string inp; ll K; string rep[30]; ll f[26][81];
void upd(ll &a,ll b){ if(a==-1)return; if(b==-1){ a=-1; return; } a+=b; if(a>1e15)a=-1; }
char reduceK(){ char chr=inp[0]; bool vis[30]; stack<char> st; memset(vis,0,sizeof(vis)); while(!vis[chr-'a']){ st.push(chr); vis[chr-'a']=1; chr=rep[chr-'a'][0]; }
int cycle=1; while(st.top()!=chr){ cycle++; st.pop(); } st.pop();
int pre=st.size();
if(K<=54)return '\0'; if(K-pre<=54)return '\0'; K-=pre; K=K-(K-54)/cycle*cycle; return chr; }
char solve(ll idx,string str,int p){ if(p==0){ return str[idx-1]; } for(int i=0;i<str.size();i++) { if (f[str[i] - 'a'][p] == -1 || f[str[i] - 'a'][p] >= idx)return solve(idx, rep[str[i] - 'a'],p-1); idx-=f[str[i] - 'a'][p]; } assert(false); }
int main(){ ios::sync_with_stdio(false); cin>>inp;
for(int i=0;i<26;i++){ cin>>rep[i]; f[i][1]=rep[i].size(); } for(int i=0;i<26;i++)f[i][0]=1; cin>>K; for(int p=2;p<=80;p++){ for(int i=0;i<26;i++){ for(int k=0;k<rep[i].size();k++){ upd(f[i][p],f[rep[i][k]-'a'][p-1]); } } } char start=reduceK();
int qlen;cin>>qlen; while(qlen--){ ll idx;cin>>idx; if(start=='\0')cout<<solve(idx,inp,K)<<endl; else cout<<solve(idx,rep[start-'a'],K-1)<<endl; }
}
|