HDU 4357
题意:两个字符串s1,s2,一次操作可以将两个字符位置交换,且被交换的字符ascii码会+1,即'a'变成'b','b'变成'c',...,'z'变成'a'。操作不限次数,问能否将s1变成s2。
题解:归纳证明一下长度>2的排列(a,b,c,...)能经过若干次操作交换成别的排列。
长度为3时,初始设为(a,b,c),先让a和b交换13次,(b+13,a+13,c),接下来c和a,b分别交换两次会变成(b+15,a+15,c+4),发现c的增长速度是a和b的增长速度的两倍,那么考虑一下从(b+13,a+13,c)开始,每轮c和a,b分别交换1次,c进行13次交换后,得到(c+26,b+26,a+26)=(c,b,a),这样子就可以从(a,b,c)->(c,b,a)了,这个映射是a->c,c->a的,也就是说如果固定中间的那位,其他两位可以随便换,就是3*2,而3!=6,所以对于长度为3而言是可以从一个排列变成任意一个其他的排列的。
更长的可以接着归纳交换出来,只不过循环节可能会有所不同。
所以计算一下\(\sum_{i=1}^{size}(abs(s[2][i]-s[1][i]))\)是不是偶数,是偶数就肯定能从一个排列交换成另一个排列。奇数显然不行。
需要特判一下长度=2的情况,因为有可能a1不和a2对应,a1可以和b2对应,讨论一下就好。
#include<bits/stdc++.h>
using namespace std;
const int N=100;
int T,cnt;
char s1[N],s2[N];
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%s%s",s1+1,s2+1);
int l=strlen(s1+1);
printf("Case #%d: ",++cnt);
if(l>2)
{
int dis=0;
for(int i=1;i<=l;i++)
dis+=abs(s1[i]-'a'+s2[i]-'a');
if(dis&1) puts("NO");
else puts("YES");
}
else
{
int a1=s1[1]-'a';
int a2=s1[2]-'a';
int b1=s2[1]-'a';
int b2=s2[2]-'a';
int dis=(b1-a1+26)%26;
if(dis%2==0&&(a2+dis)%26==b2)
puts("YES");
else
{
dis=(b2-a1+26)%26;
if(dis%2==1&&(a2+dis)%26==b1)
puts("YES");
else puts("NO");
}
}
}
return 0;
}

浙公网安备 33010602011771号