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;
}
posted @ 2020-08-21 20:49  JWizard  阅读(76)  评论(0)    收藏  举报