ZOJ 3817Chinese Knot(The 2014 ACM-ICPC Asia Mudanjiang Regional First Round)

思路: 将4个串每个串都反向这样得到新的四个串一共8个串,对于母串每个位置检测这个串能不能放进去,hs或者后缀数组都可以。然后dp[i][j]  (0<i<len  0<=j<8)表示长度为i以第j个串结尾能不能到达,如果能 那么 就可以i+1位置利用原来处理出来的来转移。要注意开头结尾即可。

注意:以第i个串结尾  那么下个串 就不能用第i个串的反向串。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<time.h>
#include<string>
#define REP(i,n) for(int i=0;i<n;++i)
#define REP1(i,a,b) for(int i=a;i<=b;++i)
#define REP2(i,a,b) for(int i=a;i>=b;--i)
#define MP make_pair
#define LL long long
#define ULL unsigned long long
#define X first
#define Y second
#define MAXN 100050
using namespace std;
int pre[MAXN][8];
bool bo[MAXN][8];
bool dp[MAXN][8];
bool ed[MAXN][8];
ULL hs[9][MAXN];
ULL p[MAXN];
int id[8][MAXN];
char s[9][MAXN];
int len[9];
void makehs(int id){
    hs[id][0]=1;
    for(int i=1;i<=len[id];++i)
        hs[id][i]=hs[id][i-1]*31+s[id][i-1]-'a'+1;
}
ULL geths(int id,int l,int r){
    l--;
    return hs[id][r]-hs[id][l]*p[r-l];
}
int q[MAXN];
int tail;
void out(int cid,int l,int r)
{
    for(int i=r;i>=l;--i)
        q[tail++]=id[cid][i];
}
int main() {
    p[0]=1;
    for(int i=1;i<MAXN;++i)p[i]=p[i-1]*31;
    int tt,n,m;
    scanf("%d",&tt);
    while(tt--)
    {
        scanf("%d%d",&n,&m);
        memset(bo,0,sizeof(bo));
        memset(dp,0,sizeof(dp));
        memset(ed,0,sizeof(ed));
        memset(pre,-1,sizeof(pre));
        int cid=1;
        for(int i=0;i<4;++i){
            scanf(" %s",s[i*2]);
            len[i*2]=len[i*2+1]=strlen(s[i*2]);
            for(int j=0;j<len[i*2];++j)
            {
                s[i*2+1][j]=s[i*2][len[i*2]-j-1];
                id[i*2][j]=cid;
                id[i*2+1][len[i*2]-j-1]=cid++;
            }
            makehs(i*2);
            makehs(i*2+1);
        }
        scanf(" %s",s[8]);
        len[8]=strlen(s[8]);
        makehs(8);
        //整串转移
        for(int i=0;i<m;++i){
            for(int j=0;j<8;++j){
                if(i+len[j]<=m){
                    ULL tmp1=geths(8,i+1,i+len[j]);
                    ULL tmp2=geths(j,1,len[j]);
                    if(tmp1!=tmp2)continue;
                    bo[i][j]=true;
                }
            }
        }

        //开头
        for(int i=0;i<m;++i){
            for(int j=0;j<8;++j){
                if(len[j]>i){
                    ULL tmp1=geths(8,1,i+1);
                    ULL tmp2=geths(j,len[j]-i,len[j]);
                    if(tmp1!=tmp2)continue;
                    dp[i][j]=true;
                }
            }
        }

        //结尾
        for(int i=0;i<m;++i){
            for(int j=0;j<8;++j){
                if(len[j]>len[8]-i){
                    ULL tmp1=geths(8,i+1,len[8]);
                    ULL tmp2=geths(j,1,len[8]-i);
                    if(tmp1!=tmp2)continue;
                    ed[i][j]=true;
                }
            }
        }

        int pos=-1,posx,flag=0,fol;
        //转移
        for(int i=0;i<m;++i){
            for(int j=0;j<8;++j){
                if(!dp[i][j])continue;
                if(i==m-1){
                    pos=i;
                    posx=j;
                    flag=1;
                    break;
                }
                for(int k=0;k<8;++k){
                    if((j^k)==1)continue;
                    if(!ed[i+1][k])continue;
                    pos=i;
                    posx=j;
                    fol=k;
                    flag=1;
                    break;
                }
                for(int k=0;k<8;++k){
                    if((j^k)==1)continue;
                    if(!bo[i+1][k])continue;
                    dp[i+len[k]][k]=true;
                    pre[i+len[k]][k]=j;
                }
            }
            if(flag)break;
        }
        if(flag==0)
        {
            puts("No solution!");
            continue;
        }
        tail=0;
        if(pos!=m-1){
            out(fol,0,m-pos-2);
        }
        while(posx!=-1){
            if(len[posx]>pos+1)out(posx,len[posx]-pos-1,len[posx]-1);
            else out(posx,0,len[posx]-1);
            int tmpx=posx;
            posx=pre[pos][posx];
            pos=pos-len[tmpx];
        }
        for(int i=tail-1;i>0;--i)printf("%d ",q[i]);
        printf("%d\n",q[0]);
    }
    return 0;
}
/*
1
3 3
abc
abc
abc
abc
baa

*/

 

转载于:https://www.cnblogs.com/L-Ecry/p/3961131.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值