看到这个题不要方。
毕竟是第一道题,解法肯定不难。
思考:
首先看看一个序列 1 2 3 4 5 6… 这里我们只先猜想六位,
这个序列通过这种交换方式可以得到如何如何的规律~。
①必须换前缀。
②只能换偶数。
我们可以试着看看这个序列 1 2 3 4 5 6 可以得到什么样子的序列
*1 2 3 4 5 6
①换前两个 、、前四个 、、前六个
*2 1 3 4 5 6
*4 3 2 1 5 6
*6 5 4 3 2 1
再来一遍。
对于 2 1 3 4 5 6 换前四个 前6 个
*4 3 1 2 5 6 —->
*6 5 4 3 1 2 —->
对于 4 3 2 1 5 6 换前两个 前六个。
*3 4 2 1 5 6
*6 5 1 2 3 4
对于 6 5 4 3 2 1 换前两个 前 4 个
*5 6 4 3 2 1
*3 4 5 6 2 1
其实耐心写完是很容易发现规律的。。
然而并没有耐心。
可以注意到 对于最开始的1 2 3 4 5 6
相邻的两个数 (1 2) (3 4) (5 6 )
在之后的变换中都是连续的嘛,
姑且把 1 2 3 4 5 6
当做 a b c 每次可以换奇数个前缀和。
也就是说我们可以乱搞了。
换一换嘛。
a b c
我可以让a换到任意的位置。
b a c
或者
b c a
同理 b ,c 当然也可以换到任意一个位置。
a b c
a c b
和
c a b
a c b
好像全排列都可以= =
然后就出来了。
可以发现 (1,2)(3, 4) (5,6 ) 组成的全排列其实都可以得到。
而且 不一定是 (1,2) 也可以是 (2, 1)
因为
1 2 3 4 5 6
可以得到
2 1 3 4 5 6
和上面的结论是一样的。
(开始枚举的时候已经加粗了,说明 a b 或者 b a 可以插入序列中任何一个位置 。然后所以任何一个 序列的开头两个字母都可以插入序列中任何一个位置。)
从而得出任意成对的两个字符都可以插入序列中任何一个位置(当然是偶数的为)
所以对于string 1 以及 string 2
我们直接 枚举 string 2 的任意 两个配对的字符 在string1 中是否以配对的方式出现即可。
如
**re**do**po**tc
do**ct**po**er**
我们发现是可以两两配对的。
所以n*n枚举所有搭配。
然后 T*T/4 枚举所有配对方式。
如果是奇数位数
如果最后一位不相同。
不管怎么换都换不过来。。
特判即可。
1 2 3
3 2 1
是不是怎么搞最后一位都不能从 1 变成 3 嘛。
然后 时间刚好过。虽然数据很水。
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int T,n,ans;
string A[51];
int len[51];
int flag[51];
bool cmp(string a,string b)
{
return a.length()<b.length();
}
bool work(int i,int j)
{
int used1[51],used2[51];
memset(used1,0,sizeof(used2));
memset(used2,0,sizeof(used2));
if((len[i]==len[j])&&(len[i]&1))
if(A[i][len[i]-1]!=A[j][len[j]-1])
return false;
char s1,s2,p1,p2;
for (int k=1;k<=len[i]/2;k++){
if(used1[2*(k-1)]==1) continue;
if(used1[2*(k-1)+1]==1) continue;
s1=A[i][2*(k-1)];
s2=A[i][2*(k-1)+1];
bool flag=false;
for (int p=1;p<=len[i]/2;p++){
p1=A[j][2*(p-1)];
p2=A[j][2*(p-1)+1];
if(used2[2*(p-1)]==1) continue;
if(used2[2*(p-1)+1]==1) continue;
if((s1==p1)&&(s2==p2)||((s1==p2)&&(s2==p1))){
used1[2*(k-1)]=used1[2*(k-1)+1]=used2[2*(p-1)]=used2[2*(p-1)+1]=1;
flag=true;
break;
}
}
if(flag==false){
return false;
}
}
return true;
}
int main()
{
freopen("kahuucino.in","r",stdin);
//freopen("kahuucino.out","w",stdout);
cin>>T;
while(T--)
{
cin>>n;
ans=0;
memset(flag,0,sizeof(flag));
memset(len,0,sizeof(len));
for (int i=1;i<=n;i++) {
cin>>A[i];
len[i]=A[i].length();
}
for (int i=1;i<=n;i++){
for (int j=i+1;j<=n;j++){
if((flag[i]!=0)||(flag[j]!=0)) continue;
if(len[i]!=len[j]) continue;
else {
bool pd=work(i,j);
if(pd==true){
flag[i]=1;
flag[j]=1;
}
}
}
}
for (int i=1;i<=n;i++)
if(flag[i]==0) ans++;
cout<<ans<<endl;
}
return 0;
}