ZOJ 4110 Strings in the Pocket 回文串+马拉车

本文探讨了如何通过反转字符串的一部分来使两个字符串相等的问题。详细分析了两种情况:字符串完全相同时利用Manacher算法计算回文子串长度,以及字符串部分不同时查找可反转区间的算法实现。

BaoBao has just found two strings  and  in his left pocket, where  indicates the -th character in string , and  indicates the -th character in string .

As BaoBao is bored, he decides to select a substring of  and reverse it. Formally speaking, he can select two integers  and  such that  and change the string to .

In how many ways can BaoBao change  to  using the above operation exactly once? Let  be an operation which reverses the substring , and  be an operation which reverses the substring . These two operations are considered different, if  or .

Input

There are multiple test cases. The first line of the input contains an integer , indicating the number of test cases. For each test case:

The first line contains a string  (), while the second line contains another string  (). Both strings are composed of lower-cased English letters.

It's guaranteed that the sum of  of all test cases will not exceed .

Output

For each test case output one line containing one integer, indicating the answer.

Sample Input

2
abcbcdcbd
abcdcbcbd
abc
abc

Sample Output

3
3

Hint

For the first sample test case, BaoBao can do one of the following three operations: (2, 8), (3, 7) or (4, 6).

For the second sample test case, BaoBao can do one of the following three operations: (1, 1), (2, 2) or (3, 3).

题意:给你两个长度相等的字符串,要求S串通过反转变成T串,能够反转的区间个数是多少;(或者叫做交换更好理解一点)

分析:这里需要注意两种情况

1.当两个字符串字符相等的时候,你需要求一下这两个字符串的回文串的长度,其实在这题当中需要用到的是Manacher中Len数组(Len数组定义就是以当前字符能够达到的回文字符串的半径?,这里还要包括其本身,不同的博客定义可能不相同,但是意义都是一样的),通过这个字符串就能求出反转的子字符串的长度

2.当两个字符串不是相同的时候,你需要找到这个S串中最左和最右不相等的端点,然后看这个区间里面的字符是否符合反转要求,如果里面的字符反转后不相等,那么就输出0,否则的话就以这两个端点向两端去扩展,扩展的话只有是相等的字符才行;

什么意思呢???

比如这个字符串

aabacbab

aabcabab这两个只能是扩展到第二个字符就截止,但如果是下面这种情况:

aabacbaa

aabcabaa

这样就能扩展到第一个字符(上下两种都是从下标1开始的,别混了?)

 

#include <iostream>
#include <algorithm>
#include <string>
#include <map>
#include <cstring>
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <set>
#include <stack>
using namespace std;
typedef long long ll;
const int N = 2e6+100;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
const int MOD=1e9+7;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Abs(x) ((x)>=0?(x):-(x))
char str1[N],str2[N],str[3*N];
int vis[N],Len[N*3];
void init(int x){
    int k=0;
    Len[k]=0;str[k++]='$';
    int len=strlen(str1);
    for(int i=x;i<len;i++){
        Len[k]=0;str[k++]='#';
        Len[k]=0;str[k++]=str1[i];
    }
    Len[k]=0;str[k++]='#';
    Len[k]=0;str[k++]='\0';
}
int Manacher(){
    Len[0]=0;
    int mx=0,id=0;
    int len=strlen(str);
    for(int i=0;i<len;i++){
        if(i<mx)
            Len[i]=min(mx-i,Len[2*id-i]);
        else
            Len[i]=1;
        while(str[i-Len[i]]==str[i+Len[i]]) Len[i]++;
        if(Len[i]+i>mx){
            mx=Len[i]+i;
            id=i;
        }
    }
//    printf("Len数组:\n");
//    for(int i=0;i<len;i++){
//        printf("%d ",Len[i]);
//    }
//    printf("\n");
    return len;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
    int t;
    scanf("%d\n",&t);
    while(t--){
        scanf("%s%s",str1,str2);
        int len=strlen(str1);
        if(strcmp(str1,str2)==0){
            init(0);
            ll ans=0;
            int k=Manacher();
            for(int i=0;i<k;i++) ans+=Len[i]/2;
            printf("%lld\n",ans);
            continue;
        }
        int cnt=0;
        for(int i=0;i<len;i++){
        if(str1[i]!=str2[i]) vis[cnt++]=i;
        }

        if(cnt&1) { printf("0\n"); continue;}//当存在奇数个不同的字符的时候,肯定是不管是怎么交换都是不满足题意的
        int flag=0;
        for(int i=vis[0],j=vis[cnt-1];i<j;i++,j--){
            if(str1[j]!=str2[i]||str1[i]!=str2[j]){
                flag=1;break;
            }
        }
        if(flag)  {printf("0\n");continue;}
        int ans=1;

        for(int i=vis[0]-1,j=vis[cnt-1]+1;i>=0&&j<len;i--,j++){
            if(str1[i]==str2[j]&&str2[j]==str1[i]) ans++;
            else break;

        }
        printf("%d\n",ans);
    }
    return 0;
 }

 

先展示下效果 https://pan.quark.cn/s/a4b39357ea24 遗传算法 - 简书 遗传算法的理论是根据达尔文进化论而设计出来的算法: 人类是朝着好的方向(最优解)进化,进化过程中,会自动选择优良基因,淘汰劣等基因。 遗传算法(英语:genetic algorithm (GA) )是计算数学中用于解决最佳化的搜索算法,是进化算法的一种。 进化算法最初是借鉴了进化生物学中的一些现象而发展起来的,这些现象包括遗传、突变、自然选择、杂交等。 搜索算法的共同特征为: 首先组成一组候选解 依据某些适应性条件测算这些候选解的适应度 根据适应度保留某些候选解,放弃其他候选解 对保留的候选解进行某些操作,生成新的候选解 遗传算法流程 遗传算法的一般步骤 my_fitness函数 评估每条染色体所对应个体的适应度 升序排列适应度评估值,选出 前 parent_number 个 个体作为 待选 parent 种群(适应度函数的值越小越好) 从 待选 parent 种群 中随机选择 2 个个体作为父方和母方。 抽取父母双方的染色体,进行交叉,产生 2 个子代。 (交叉概率) 对子代(parent + 生成的 child)的染色体进行变异。 (变异概率) 重复3,4,5步骤,直到新种群(parentnumber + childnumber)的产生。 循环以上步骤直至找到满意的解。 名词解释 交叉概率:两个个体进行交配的概率。 例如,交配概率为0.8,则80%的“夫妻”会生育后代。 变异概率:所有的基因中发生变异的占总体的比例。 GA函数 适应度函数 适应度函数由解决的问题决定。 举一个平方和的例子。 简单的平方和问题 求函数的最小值,其中每个变量的取值区间都是 [-1, ...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值