首页 > 编程语言 > 详细

字符串有关算法综合

时间:2016-04-09 16:39:54      阅读:205      评论:0      收藏:0      [点我收藏+]

稍微做一点吧。

好像序列自动机还没有写过…

串长为n的串共有n+1个节点,除了串中的n个节点,还有一个空的根节点放在串首。每个节点至多有26条出边,每条边连向它之后的第一个字符。

串中的任意一个子序列对应了一条根到某个节点的路径。且每条路径对应一个不同的子序列。

每个节点的parent是这个字母上一次出现的位置。更新只要沿parent指针扫描即可。

FJOI2016 所有公共子序列问题

这题暴力建trie能过80真是悲伤(因为按FJOI命题风格这题没有写数据范围

建完序列自动机暴力DP即可

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <limits>
#include <set>
#include <map>
using namespace std;
#define SZ 3333
int ys[2333],fys[2333];
#define M 60
struct Seq_A_M
{
int par[SZ],ch[SZ][62],lst[62],C,rot;
Seq_A_M()
{
    C=rot=1;
    for(int i=0;i<M;i++) lst[i]=rot;
}
void ins(char c)
{
    ++C; par[C]=lst[c];
    for(int i=0;i<M;i++)
    {
        for(int g=lst[i];g&&!ch[g][c];g=par[g]) ch[g][c]=C;
    }
    lst[c]=C;
}
}S_A,S_B;
int n,m;
typedef long long ll;
ll dp[SZ][SZ];
char x[SZ],y[SZ];
ll getdp(int a,int b)
{
    if(!a||!b) return 0;
    if(dp[a][b]>=0) return dp[a][b];
    long long ans=1;
    for(int i=0;i<M;i++) ans+=getdp(S_A.ch[a][i],S_B.ch[b][i]);
    return dp[a][b]=ans;
}
char s[233333];
void tryy(int a,int b,int cl)
{
    if(!a||!b) return;
    s[cl]=0; printf("%s\n",s);
    for(int i=0;i<M;i++)
    {
        s[cl]=fys[i]; tryy(S_A.ch[a][i],S_B.ch[b][i],cl+1);
    }
}
int main()
{
    for(int i=A;i<=Z;i++) ys[i]=i-A, fys[i-A]=i;
    for(int i=a;i<=z;i++) ys[i]=i-a+26, fys[i-a+26]=i;
    int k=0;
    scanf("%d%d%s%s%d",&n,&m,x,y,&k);
    for(int i=0;i<n;i++) S_A.ins(ys[x[i]]);
    for(int i=0;i<m;i++) S_B.ins(ys[y[i]]);
    if(k==1) tryy(1,1,0);
    memset(dp,-1,sizeof(dp));
    printf("%lld\n",getdp(1,1));
}

字符串有关算法综合

原文:http://www.cnblogs.com/zzqsblog/p/5371808.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!