参考:CCF CSP题解:字符串变换(str)(202409-2)_csp字符串变换-CSDN博客
原题目:TUOJ
针对该参考(第一行链接)代码(一会儿TE80分,一会AC100分),Gemini给出了了超时原因和优化建议:
超时原因(时间复杂度):
由于循环周期 T 最大可以达到 63,最坏情况下 k 接近 63。对于 M <= 1000 个查询和 的字符串,总复杂度约为
,即
万次操作。
虽然 630 万次操作对于现代计算机来说很快,但这不是最优解,尤其是在字符集更大的类似问题中。真正的最优解法应该是:
更优的解决方案(预存路径,空间换时间):
在 initFunc 阶段,不仅仅计算周期 ,而是直接存储每个字符
沿着周期路径变换
到
次后的结果。
-
预处理:
path[ch][i]存储字符变换
次后的结果。
-
查询:最终结果字符
。
这样,每次查询的字符变换时间复杂度降为 ,总复杂度为
,极大地提高了效率,并且是更优雅的解法。
在官网运行:AC,100分

#include <iostream>
#include <unordered_map>
#include <string>
#include <vector>
using namespace std;
int n;
string str;
unordered_map<int,vector<int>> path;
int T[256] = {0};//int T[256] = {};都可初始化为0
unordered_map<int,int> trans;
void initFunc();
string transFunc(int k);
int main(){
getline(cin,str);//cin>>str;会在空格处断开!
str = str.substr(1,size(str)-2);
cin>>n; cin.ignore();
initFunc();
int m;
cin>>m;
int k;
while(m--){
cin>>k;
cout<<"#"+transFunc(k)+"#"<<'\n';
}
}
void initFunc(){
int n_it = n;
string tmp;
while(n_it--){
getline(cin,tmp);
char ch_frm = tmp[1];
char ch_to = tmp[2];
if(ch_frm != ch_to){//自环不处理
T[ch_frm] = -1;
trans[ch_frm] = ch_to;
}
}
for(int i = 0;i < 256;i++){
if(T[i] != -1) continue;
int newCh = i;
path[i].emplace_back(i);
do{
newCh = trans[newCh];
path[i].emplace_back(newCh);
}while(newCh != i);
path[i].pop_back();
T[i] = path[i].size();
}
}
string transFunc(int k){
string res = str;
for(char& ch : res){
if(!path.count(ch)) continue;//没有映射关系,不处理
int index = k%T[ch];
// cout<<ch<<' '<<k<<' ';
ch = char(path[ch][index]);
// cout<<ch<<'\n';
}
return res;
}

1977

被折叠的 条评论
为什么被折叠?



