[CSP]字符串变换

字符串变换

时间限制: 1.0 秒

空间限制: 512 MiB

相关文件: 题目目录(样例文件)

题目描述

本题涉及字符包括大小写字母(A-Za-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(b0 都被替换为 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的整数,再写个函数转换回来就行了。

        并查集写完发现并没有什么软用,,,

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值