字符串变换
时间限制: 1.0 秒
空间限制: 512 MiB
相关文件: 题目目录(样例文件)
题目描述
本题涉及字符包括大小写字母(A-Z
和 a-z
)、数字(0-9
)和空格共 6363 种。在这个字符集合上,小 P 定义了一个字符替换函数 f(ch)f(ch),表示将字符 chch 替换为 f(ch)f(ch)。 例如 f(a)=bf(a)=b 表示将 a
替换为 b
,f(b)=0f(b)=0 表示将 b
替换为 0
。 进而可以将其扩展为字符串变换函数 F(s)F(s),表示对字符串 s
进行变换,将 s
中每个字符 chch 都替换为 f(ch)f(ch)。
字符替换函数 ff 可表示为 nn 个字符对 (ch1,ch2)(ch1,ch2),即 f(ch1)=ch2f(ch1)=ch2。
-
nn 个字符对中,ch1ch1 两两不同,即不会出现同时定义了 f(a)=bf(a)=b 和 f(a)=0f(a)=0 的情况;
-
未定义的 f(ch)f(ch),可视为 f(ch)=chf(ch)=ch,即字符 chch 保持不变;
-
函数 ff 为单射,即当 ch1≠ch2ch1=ch2 时有 f(ch1)≠f(ch2)f(ch1)=f(ch2),例如不会同时有 f(b)=0f(b)=0 和 f(0)=0f(0)=0(
b
和0
都被替换为0
)。
现给定初始字符串 s
,试处理 mm 个查询:每个查询包含一个正整数 kk,询问对初始字符串 s
变换 kk 次后的结果 Fk(s)Fk(s)。
输入格式
从标准输入读入数据。
输入共 n+4n+4 行。
输入的第一行包含一个字符串,形如 #s#
,即用两个井号字符 #
将初始字符串 s
囊括其中。
输入的第二行包含一个正整数 nn,表示组成函数 ff 的字符对数;接下来 nn 行每行输入一个形如 #xy#
的字符串,表示 f(x)=yf(x)=y。
输入的第 n+3n+3 行包含一个正整数 mm,表示查询的个数;下一行包含空格分隔的 mm 个正整数 k1,k2,⋯ ,kmk1,k2,⋯,km,表示 mm 个查询。
输出格式
输出到标准输出。
输出共 mm 行,依次输出 mm 个查询的结果;输出时每行同样是一个形如 #s#
的字符串,即用两个井号把变换后的字符串 s
括起。
样例输入
#Hello World#
6
#HH#
#e #
# r#
#re#
#oa#
#ao#
3
1 2 3
样例输出
#H llarWaeld#
#HrlloeWo ld#
#Hella Warld#
子任务
前 6060 的测试数据保证初始字符串 s
仅包含小写字母,且输入的 nn 个字符对也皆为小写字母(即保证小写字母仅会被替换为小写字母);
前 8080 的测试数据保证查询数量 m≤10m≤10、变换次数 k≤100k≤100;
全部测试数据保证 0<n≤630<n≤63、0<m≤1030<m≤103、0<k≤1090<k≤109 且初始字符串 s
包含不超过 100 个字符。
提示
由于读入的字符串中包含空格字符,推荐使用按行读取的方式,避免读入时跳过空格(如 cin
直接读入字符串)。
C
语言:可以使用 fgets()
函数读入整行,fgets(s, count, stdin)
会从标准连续输入读入至多 count - 1
个字符,并存入字符数组 s
,直到遇到换行符或文件末尾为止。在前一种情况下,s
结尾处会存有读入的换行符。也可使用 getchar()
函数逐个字符读入,如 char ch = getchar();
,这种方法需手动判断是否到达行末,即返回值是否为 \n
。
C++
:可以使用 std::getline()
函数读入整行:std::getline(std::cin, s)
会从标准输入读入字符,并存入字符串 std::string s
中,直到换行符或文件末尾为止。在前一种情况下,换行符会从标准输入中读出,但不会存入字符串 s
中。
Python
:使用 input()
函数即可读入整行。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
int n,m;
string str,s;
int father[1000],Next[1000],Time[1000];
void init()
{
for(int i=1;i<=63;i++)
{
father[i]=i;
Next[i]=i;
}
}
int find_set(int x)
{
return x==father[x]?x:father[x]=find_set(father[x]);
}
void merge_set(int a,int b)
{
int x=find_set(a);
int y=find_set(b);
if(x!=y)
{
father[y]=x;
}
}
int transfer(char c)
{
if(c>='0'&&c<='9')return c-'0'+1;
else if(c>='a'&&c<='z')return c-'a'+11;
else if(c>='A'&&c<='Z')return c-'A'+37;
else return 63;
}
char transback(int c)
{
if(c>=1&&c<=10)return c+'0'-1;
else if(c>=11&&c<=36)return c+'a'-11;
else if(c>=37&&c<=62)return c+'A'-37;
else return ' ';
}
void input()
{
for(int i=0;i<n;i++)
{
getline(cin,s);
s.erase(s.size()-1);
s.erase(0,1);
//cout<<endl<<s<<endl;
int a,b;
a=transfer(s[0]);
b=transfer(s[1]);
//cout<<a<<' '<<b<<endl;
merge_set(a,b);
Next[a]=b;
}
}
int period(int n)
{
int cnt=1;
int tmp=n;
n=Next[n];
while(tmp!=n)
{
cnt++;
n=Next[n];
}
return cnt;
}
void dispute()
{
for(int i=0;i<64;i++)
{
Time[i]=period(i);
//cout<<1;
}
}
string change(int k)
{
string s=str;
int cnt;
for(auto &i:s)
{
cnt=k;
cnt%=Time[transfer(i)];
if(!cnt)continue;
while(cnt--)
{
i=transback(Next[transfer(i)]);
}
}
return s;
}
int main()
{
init();
getline(cin,str);
str.erase(str.size()-1);
str.erase(0,1);
//cout<<str<<endl;
cin>>n;getchar();
//cout<<n;
input();
dispute();
cin>>m;getchar();
for(int i=0;i<m;i++)
{
int k;scanf("%d",&k);
string ans=change(k);
cout<<"#"<<ans<<"#"<<endl;
}
return 0;
}
/*
#Hello World#
6
#HH#
#e #
# r#
#re#
#oa#
#ao#
9
1 2 3 4 5 6 7 8 9
*/
简单说一下思路:将几个字符转换例如从a到b,定义next表示a的下一个是b,因为题目描述所以每一个字母都会有一个环(也可能是从自己到自己的环)而题目要求的k次变换对于单个字符来说,k%(环的长度)次变换跟k次变换结果是一致的。
关于字符处理就是把所有可能输入字符转换成1-63的整数,再写个函数转换回来就行了。
并查集写完发现并没有什么软用,,,