SGU 411Petya the Hero(最长公共回文子串,AC自动机+n^2判断回文)(学习后缀数组的前奏)

411. Petya the Hero
Time limit per test: 0.25 second(s)
Memory limit: 65536 kilobytes
input: standard
output: standard

Petya has come back from the Berland-Birland War, and now he is fond of gathering his friends and narrating his heroic deeds. You have probably heard the story telling that Petya, being isolated, captured two Birland officers single-handed, than, using their clothes and having got to know the password, penetrated into the army base of the enemy, forced the controlling system out of action and helped Berland army to seize the base. This story was also heard by Colonel Kruglyakovsky, who was especially interested in a detail. That is the way Petya managed to find out the password for entering the army base with his poor knowledge of Birland language. Called by the colonel young hero explained, that although Birland speech wasn't clear to him, it wasn't too difficult to write it down. At first Petya interrogated the captives and wrote down the speech of each one as a string of latin letters. He knew that Birland valid passwords could be read the same way in either direction, i.e. they were palindromes. So he had to use the program, searching for the longest common substring of two strings, which was valid as a password. After hearing the answer, Colonel Kruglyakovsky declared, that this program could be very useful for interrogation captives and for decoding secret messages... As far as Petya certanly hadn't any program, he asked you for help. 
Input
The input file contains two non-empty strings that consist of lowercase latin letters (
'a'
-
'z'
). The length of each string doesn't exceed 2000 symbols. The strings contain at least one common letter. 
Output
Output the password obtained by the program Petya has described. If there are several possible passwords, output any of them. 
Example(s)
sample input
sample output
abacaba
abracab
aca

sample input
sample output
abbab
babbab
abba


本题题意描述SJB。说了那么多没用的最后其实就是要 求两个字符串的最长公共回文子串的长度

具体描述如下:

给定两个字符串,s1,s2 且 1=<|s1|,|s2|<=2000;

求s1,s2的最长公共回文子串subs的长度

一。subs是s1的子串,subs也是s2的子串

二。subs是回文的,palindromic;

三。subs是所有子串中最长的

求|subs|;


这是暑假集训的一道题,当时没做出来,因为根本不会字符串的一些神器。今天在朋友的提醒下,弄出来了

我还不会后缀数组和height数组,我不知道用后缀数组神器能否O(n)解决,去看了下别人代码,好像需要O(n^2)解决

毕竟这题n=2000,如果可以O(n)解决,应该会给n=10^5吧。我不清楚,待我学会后缀数组神器后,再把这题过一遍。


我的方法是AC自动机+n^2判断回文

既然n=2000,n^2算法可以承受,也可以存储下,就n^2判断每个子串是否回文

方法是以每个串为中心向两端拓展,若回文,则palin[i][j]=true,遇到不回文break即可

(注意到这里palin[][]数组初始化时候是false情况,所以只需把所有回文情况找到,改为true即可)

同时,再以每2个字符串中间为中心,向两端拓展,若回文,则palin[i][j]=true,遇到不回文则break。


假设输入的字符串是T,S

这样子palin[i][j]表示的就是S中 i 到 j 这个子串是否回文

然后,把S的每一个子串放到AC自动机里,如果该子串是回文(通过palin数组判断),则字典树该结点权值为1,否则为0 (相信熟悉AC自动机的朋友都看得懂)

注意,这里不能把所有的子串都放到AC自动机里,因为这样子会爆内存,一开始我就那么做,一直没过

怎么办呢?分n次放入就可以了

比如,S=s0s1s2....sn-1

第一次取s0...sn-1这一段,放入自动机里,然后用T进行AC自动机搜索,判断是否有一个回文子串是T的子串

第二次取s1...sn-1这一段,重复上述过程

......

最后一次取sn-1...sn-1这一段,其实只有一个字符,重复上述过程

不断维护子串的最长长度,同时记录位置即可。(题目保证一定有解)


代码如下:

//Hello. I'm Peter.
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define pb(a) push_back(a)
#define clr(a) memset(a,0,sizeof(a))
#define clr_minus1(a) memset(a,-1,sizeof(a))
#define clr_INT(a) memset(a,INT,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_false(a) memset(a,false,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define pi acos(-1.0)
#define eps 1e-6
#define MOD 1000000007
#define MAXN 10100
#define N 2014
#define M 26
bool palin[N][N];
void Palin_ornot(char *s,int len){
    int t=1;
    rep(i,0,len){
        t=0;
        while(i-t>=0 && i+t<len && s[i-t]==s[i+t]){
            palin[i-t][i+t]=true;
            t+=1;
        }
    }
    int t1=0,t2=0;
    rep(i,0,len-1){
        t1=i,t2=i+1;
        while(t1>=0 && t2<len && s[t1]==s[t2]){
            palin[t1][t2]=true;
            --t1,t2++;
        }
    }
}
struct Trienode{
    int from,to,len;
}trienode[MAXN];
int trie[MAXN][M],num_node,val[MAXN];
int lenup,lendown;
char up[N],down[N];
int idx(char c){
    return c-'a';
}
void init_Trie(){
    clr(trie[0]);
    num_node=1;
}
void plant_trie(char *s,int from,int to){
    int now=0,letter;
    rep(i,from,to){
        letter=idx(s[i]);
        if(!trie[now][letter]){
            trie[now][letter]=num_node;
            val[num_node]=palin[from][i]?1:0;
            trienode[num_node].from=from;
            trienode[num_node].to=i;
            trienode[num_node].len=i-from+1;
            clr(trie[num_node]);
            num_node+=1;
        }
        now=trie[now][letter];
    }
}
int nextpos[MAXN],lastpos[MAXN];
queue<int>q;
void Build_nextandlastpos(){
    clr_queue(q);
    nextpos[0]=lastpos[0]=0;
    int now=0,son=0;
    rep(i,0,M){
        son=trie[now][i];
        if(son){
            nextpos[son]=lastpos[son]=0;
            q.push(son);
        }
    }
    int nextone;
    while(!q.empty()){
        now=q.front();
        q.pop();
        rep(i,0,M){
            son=trie[now][i];
            nextone=nextpos[now];
            if(!son){
                trie[now][i]=trie[nextone][i];
                continue;
            }
            while(nextone && !trie[nextone][i]) nextone=nextpos[nextone];
            nextpos[son]=trie[nextone][i];
            lastpos[son]=val[nextpos[son]]?nextpos[son]:lastpos[nextpos[son]];
            q.push(son);
        }
    }
}
int anst,from,to;
void Caculate_ans(int x){
    if(x){
        if(trienode[x].len>anst){
            anst=trienode[x].len;
            from=trienode[x].from;
            to=trienode[x].to;
        }
    }
}
void AC_search(char *s,int len){
    int now=0,letter=0;
    rep(i,0,len){
        letter=idx(s[i]);
        now=trie[now][letter];
        if(val[now]) Caculate_ans(now);
        else if(lastpos[now]) Caculate_ans(lastpos[now]);
    }
}
int main()
{
    scanf("%s %s",up,down);
    lenup=len(up);
    lendown=len(down);
    Palin_ornot(down,lendown);
    anst=0;
    rep(i,0,lendown){
        init_Trie();
        plant_trie(down,i,lendown);
        Build_nextandlastpos();
        AC_search(up,lenup);
    }
    repin(i,from,to){
        printf("%c",down[i]);
    }
    printf("\n");
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用Matlab中的优化工具箱来求解该最大化问题。具体步骤如下: 1. 定义目标函数:将最大化问题转化为最小化问题,即将目标函数乘以-1。在Matlab中可以定义一个匿名函数来表示目标函数。 ```matlab f = @(x) -sum(Z(SGU)*C_1*Task.*L_k.*log(x(1:N))) + C_2*sum(x(N+1:end).^2/2); ``` 其中,x为优化变量,前N个元素为p_sm,后M个元素为q_sm。 2. 定义约束条件:根据题目中的约束条件,可以将p_sm限制在[0,1]的范围内。在Matlab中可以使用ineqconstr函数定义不等式约束条件。 ```matlab A = []; b = []; Aeq = []; beq = []; lb = zeros(N+M,1); ub = ones(N,1); nonlcon = @(x) []; ``` 其中,A、b、Aeq、beq、lb和ub分别表示线性等式约束、线性不等式约束、非线性等式约束、非线性不等式约束、变量下界和变量上界。nonlcon表示非线性约束条件,在本问题中为空。 3. 求解最小化问题:使用Matlab中的fmincon函数求解最小化问题。 ```matlab x0 = rand(N+M,1); [x,fval,exitflag,output] = fmincon(f,x0,A,b,Aeq,beq,lb,ub,nonlcon); ``` 其中,x0为优化变量的初始值。fval为目标函数的最小值。exitflag表示求解器的退出标志,0表示收敛,其它值表示未收敛。output为求解过程的详细信息。 4. 计算最大化问题的解:将目标函数的最小值乘以-1得到最大化问题的最优解。 ```matlab max_fval = -fval; max_p_sm = x(1:N); max_q_sm = x(N+1:end); ``` 其中,max_p_sm和max_q_sm分别为最优解中的p_sm和q_sm。 以上就是使用Matlab求解该最大化问题的基本步骤。需要注意的是,在实际应用中,还需要根据具体情况进行调试和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值