HDU 5469(Antonidas - 트리에서 문자열 일치)

17413 단어 귀속문자열dp
트리에서 문자열 일치(1≤ N≤104)
직접 폭력 트리 dp는 맵으로 저장되며, 시간이 지나면 끊길 수 있습니다. 귀환 후 맵을 정리하여 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
"
,kcase); else printf("Case #%d: Impossible
"
,kcase); } return 0; }

우리는 또한 나무 분리와hash를 사용할 수 있다. 나무의 중심 루트에 대해 루트를 통과한 열을 일치시킨 다음에 v→루트→v의 열을 빼고 답을 얻을 수 있다. 그렇지 않으면 계속 분리할 수 있다.
#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
"
,kcase); else printf("Case #%d: Impossible
"
,kcase); } return 0; }

좋은 웹페이지 즐겨찾기