【搜索】【字符串】【七中联考】

这里写图片描述

看到这个题不要方。
毕竟是第一道题,解法肯定不难。

思考:
首先看看一个序列 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值