1103: zdw与字符串
时间限制: 4 Sec 内存限制: 128 MB
提交: 38 解决: 7
[提交][状态][讨论版]
题目描述
一开始zdw有一个字符串S
给定Q个操作, 每次把S中的所有字符x替换成字符y
问Q次操作都做完后的字符串S
输入数据
- 第一行一个整数T表示数据组数
- 接下来T组数据格式如下
- 第一行一个字符串S和一个整数Q, 用一个空格隔开
- 接下来Q行, 每行两个用空格隔开的字符x,y表示把S中的所有x变成y
- 保证S,x,y中都只有小写英文字母
输出数据
- 共T行, 每行一个字符串表示该组数据的结果
样例输入
- 2
- aabac 2
- a b
- b c
- aabac 2
- b d
- a b
样例输出
- ccccc
- bbdbc
输入
输出
提示
数据范围:
T<=30
|S|<=10^5
Q<=10^5
S,x,y均由小写字母构成
保证Q的总和在3*10^5以内
思路:
方法1:将每个字母开一个集合,存储字符串中等于这个字母的下标。然后每次转移只需要合并这些集合就行了。为了合并方便,可以用list存储集合。
方法2:可以发现每个字母经过转化后会对应为1个字母。那么可以将每个字母开一个集合,存储最终将转化为这个字母的字母。这里可以用二进制来表示集合,这样可以将26个字母压缩到一个int型变量里。每一位二进制代表一个字母,合并时直接取或就行了。最后可以预处理一下每个字母最终对应的字母。
方法1:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
#define ll long long
#define inf 0x3f3f3f3f
int n;
char str[MAXN];
list<int> li[30];
list<int>::iterator it;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s%d",str,&n);
for(int i=0;i<26;i++)
li[i].clear();
for(int i=0;str[i];i++)
li[str[i]-'a'].push_back(i);
while(n--)
{
char u[2],v[2];
scanf("%s%s",u,v);
if(u[0]==v[0]) continue;
li[v[0]-'a'].splice(li[v[0]-'a'].end(),li[u[0]-'a']);
li[u[0]-'a'].clear();
}
for(int i=0;i<26;i++)
{
for(it=li[i].begin();it!=li[i].end();it++)
{
str[*it]=i+'a';
}
}
puts(str);
}
return 0;
}
方法2:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
#define ll long long
#define inf 0x3f3f3f3f
int n;
char str[MAXN];
int se[30],to[30];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s%d",str,&n);
memset(se,0,sizeof se);
for(int i=0;i<26;i++)
se[i]=1<<i;
char u[2],v[2];
while(n--)
{
scanf("%s%s",u,v);
if(u[0]==v[0]) continue;
se[v[0]-'a']|=se[u[0]-'a'];
se[u[0]-'a']=0;
}
for(int i=0;i<26;i++)
{
for(int j=0;j<26;j++)
{
if(se[i]&(1<<j)) to[j]=i;
}
}
for(int i=0;str[i];i++)
str[i]=to[str[i]-'a']+'a';
puts(str);
}
return 0;
}