HDU 5469(Antonidas-树上匹配字符串)

在一个树上 (1N104) 匹配字符串

直接暴力树dp用map存,
时间可卡过,记得递归后清map防止MLE

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<set>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (10000+10)
#define MAXM (20000+10)
typedef long long ll;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}

int n;

char c[MAXN];
char s[MAXN],s2[MAXN];
bool flag=0;
class link_table
{
public:
    void mem()
    {
        MEM(pre) MEM(edge) MEM(pre) MEM(weight) size=1;      
    }
    int edge[MAXM],next[MAXM],pre[MAXN],weight[MAXM],size;
    int n;
    void addedge(int u,int v,int w)
    {
        edge[++size]=v;
        weight[size]=w;
        next[size]=pre[u];  
        pre[u]=size;
    }
    void addedge2(int u,int v,int w){addedge(u,v,w);addedge(v,u,w);}


    set<int> f[MAXN],g[MAXN];

    void dfs(int x,int fa)
    {
        Forp(x) {
            int v=edge[p];
            if (v==fa) continue;

            dfs(v,x);

            set<int>::iterator it=f[v].begin();
            for(;it!=f[v].end();it++) {
                int p=(*it);
                if (s[p+1]==c[x]) {
                    f[x].insert(p+1);
                } 
            }
            f[v].clear();

            it=g[v].begin();
            for(;it!=g[v].end();it++) {
                int p=(*it);
                if (s2[p+1]==c[x]) {
                    g[x].insert(p+1);
                } 
            }
            g[v].clear();
        }
        if (c[x]==s[1]) f[x].insert(1);
        if (c[x]==s2[1]) g[x].insert(1);

        set<int>::iterator it;
        for (it=f[x].begin();it!=f[x].end();it++) {
            if (g[x].find(::n-(*it)+1)!=g[x].end()) {
                flag=1;
                break;
            }
        }
    }
}St;
int main()
{       
//  freopen("1002.in","r",stdin);
    int T;cin>>T;

    For(kcase,T)
    {
        flag=0;
        St.mem();
        cin>>St.n;
        For(i,St.n-1) {
            int x,y;
            scanf("%d%d",&x,&y);
            St.addedge2(x,y,1);
        }
        For(i,St.n) {
            St.f[i].clear(); St.g[i].clear();
        }
        scanf("%s",c+1);

        scanf("%s",s+1);
        n=strlen(s+1);

        For(i,n) s2[i]=s[n-i+1];
        St.dfs(1,0);
        St.f[1].clear();St.g[1].clear();
        if (flag) printf("Case #%d: Find\n",kcase);
        else printf("Case #%d: Impossible\n",kcase);

    }


    return 0;
}

我们还可以使用树分治和hash:
对于树的重心 root ,匹配出经过 root 的串,然后再减去 vrootv 的串,得到答案,否则继续分治。

#include<bits/stdc++.h>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXT (200+10)
#define MAXN (100000+10)
#define pb push_back
#define mp make_pair 
typedef long long ll;
typedef unsigned long long ull;
char C[MAXN],S[MAXN];
ull hPre[MAXN],hSuf[MAXN];
ull B[MAXN],base=31;
int n,len;

int Pre[MAXN],Next[MAXN*2],edge[MAXN*2],siz=1;
void addedge(int u,int v){
    edge[++siz]=v;
    Next[siz]=Pre[u];
    Pre[u]=siz;
}
void addedge2(int u,int v) {addedge(u,v),addedge(v,u);}

int fa[MAXN],sz[MAXN],vis[MAXN];
int que[MAXN];
int getroot(int root)
{
    int l=1,r=1; que[1]=root;fa[root]=0;
    while(l<=r)
    {
        int now=que[l];
        Forp(now)
        {
            int v=edge[p];
            if (fa[now]==v||vis[v]) continue;
            fa[v]=now;      
            que[++r]=v;
        }
        ++l;
    }
    int res=INF;
    do
    {
        int now=que[r],m=0;
        sz[now]=1;
        Forp(now)
        {
            int v=edge[p];
            if (fa[now]==v||vis[v]) continue;
            sz[now]+=sz[v];     
            m=max(m,sz[v]);
        }
        m=max(m,l-1-sz[now]);
        if (res>m)
        {
            res=m;
            root=now;
        }
    } while (--r);
    return root;
}

int used[MAXN];
int dis[MAXN];
ull ldist[MAXN],rdist[MAXN];
int go(int root ,int u)
{
    Rep(i,len+1) used[i]=0;
    int l=1,r=1; que[1]=u;
    while(l<=r) {
        int now=que[l];
        if (dis[now]<=len&&ldist[now]==hPre[dis[now]]) used[dis[now]]++;
        Forp(now)
        {
            int v=edge[p];
            if (fa[now]==v||vis[v]) continue;
            fa[v]=now;
            dis[v]=dis[now]+1;
            que[++r]=v; 
            ldist[v]=ldist[now]+B[dis[v]]*C[v];
            rdist[v]=rdist[now]+B[dis[v]-1]*C[v];

        }
        ++l;
    }

    int ans=0;
    For(i,r)
    {
        int now=que[i];
        if (dis[now]-1<=len&&hSuf[dis[now]-1] == rdist[now] ) {
            ans+=used[len+1-dis[now]];
        }
    }
    return ans;
}

bool solve(int root)
{

    root=getroot(root);
    fa[root]=0; 
    vis[root]=1;

    dis[root]=1;
    ldist[root]=C[root]; rdist[root]=0;

    int ans=go(root,root);
    Forp(root){
        int v=edge[p];
        if (vis[v]) continue;
        ans-=go(root,v);
    }
    if (ans>0) return 1; 
    Forp(root) {
        int v=edge[p];
        if (vis[v]) continue;
        if (solve(v)) return 1; 
    }

    return 0;
}

void mem()
{
    MEM(Pre) siz=1;
    MEM(vis) MEM(fa) MEM(sz) MEM(used)
}

int main()
{
//  freopen("hdu5469.in","r",stdin);
//  freopen(".out","w",stdout);

    B[1]=1;
    Fork(i,2,100000) B[i]=B[i-1]*base; 

    int T;cin>>T;
    For(kcase,T) {
        mem();      
        cin>>n;
        For(i,n-1) {
            int u,v;
            scanf("%d%d",&u,&v);
            addedge2(u,v);
        }
        scanf("%s%s",C+1,S+1);
        len=strlen(S+1);
        hPre[0]=hSuf[0]=0;
        For(i,len) hPre[i]=hPre[i-1]*base+S[i];
        reverse(S+1,S+1+len);
        For(i,len) hSuf[i]=hSuf[i-1]*base+S[i];

        int flag=solve(1);
        if (flag) printf("Case #%d: Find\n",kcase);
        else printf("Case #%d: Impossible\n",kcase);            
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值