HDU 5469 Antonidas【点分治+hash】

首先将串的前缀和后缀分别hash。
然后用树分治。

对于树分治,每一个分治的root,我们首先要加上经过root的串匹配出的答案,其次要减去 vrootv 这样的串(不合法)。
做了一些剪枝,因为如果 ans>0 ,则就是匹配到了。
如果都没有则继续进行分治。

对于匹配答案,我们记录合法的后缀,然后用前缀去匹配。

//      whn6325689
//      Mr.Phoebe
//      http://blog.csdn.net/u013007900
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
#include <functional>
#include <numeric>
#pragma comment(linker, "/STACK:1024000000,1024000000")


using namespace std;

#define eps 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LLINF 1LL<<62
#define speed std::ios::sync_with_stdio(false);

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;
typedef vector<int> vi;

#define CLR(x,y) memset(x,y,sizeof(x))
#define CPY(x,y) memcpy(x,y,sizeof(x))
#define clr(a,x,size) memset(a,x,sizeof(a[0])*(size))
#define cpy(a,x,size) memcpy(a,x,sizeof(a[0])*(size))
#define debug(a) cout << #a" = " << (a) << endl;
#define debugarry(a, n) for (int i = 0; i < (n); i++) { cout << #a"[" << i << "] = " << (a)[i] << endl; }

#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define lowbit(x) (x&(-x))

#define MID(x,y) (x+((y-x)>>1))
#define getidx(l,r) (l+r | l!=r)
#define ls getidx(l,mid)
#define rs getidx(mid+1,r)
#define lson l,mid
#define rson mid+1,r

template<class T>
inline bool read(T &n)
{
    T x = 0, tmp = 1;
    char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
template <class T>
inline void write(T n)
{
    if(n < 0)
    {
        putchar('-');
        n = -n;
    }
    int len = 0,data[20];
    while(n)
    {
        data[len++] = n%10;
        n /= 10;
    }
    if(!len) data[len++] = 0;
    while(len--) putchar(data[len]+48);
}
//-----------------------------------

const int MAXN=10010;
const ull base=31;

struct Edge
{
    int to,next;
} e[MAXN<<1];
char c[MAXN],str[MAXN];
int head[MAXN],tot;
int fa[MAXN],sz[MAXN],num[MAXN];
int root,tot_size;
int que[MAXN],n,dist[MAXN],L;
bool vis[MAXN],used[MAXN];
ull ldist[MAXN],rdist[MAXN],B[MAXN],Pre[MAXN],Suf[MAXN];

void init()
{
    for(int i=0; i<=n; i++)
    {
        vis[i]=used[i]=0;
        head[i]=-1;
    }
    tot=0;
}

void addedge(int u,int v)
{
    e[tot].to=v;
    e[tot].next=head[u];
    head[u]=tot++;
}

void get_siz(int u,int fa=-1)
{
    sz[u]=1;
    int v;
    for(int i=head[u]; ~i; i=e[i].next)
    {
        v=e[i].to;
        if(!vis[v] && v!=fa)
        {
            get_siz(v,u);
            sz[u]+=sz[v];
        }
    }
}

void get_root(int u,int fa,int &root)
{
    num[u]=0;
    int v;
    for(int i=head[u]; ~i; i=e[i].next)
    {
        v=e[i].to;
        if(!vis[v] && v!=fa)
        {
            get_root(v,u,root);
            num[u]=max(num[u],sz[v]);
        }
    }
    num[u]=max(num[u],tot_size-sz[u]);
    if(num[u]<num[root]) root=u;
}

int go(int u)
{
    int l=0,r=0;
    int ans=0;
    for(que[r++]=u; l<r; l++)
    {
        int now=que[l];
        if(dist[now]<L && rdist[now]==Suf[dist[now]])
            used[dist[now]]++;
        for(int i=head[now]; ~i; i=e[i].next)
        {
            int v=e[i].to;
            if(vis[v]||fa[now]==v)  continue;
            fa[v]=now;
            dist[v]=dist[now]+1;
            ldist[v]=ldist[now]+c[v-1]*B[dist[v]];
            rdist[v]=rdist[now]+c[v-1]*B[dist[v]-1];
            que[r++]=v;
        }
    }
    for(int i=0; i<r; i++)
    {
        int v=que[i];
        if(dist[v]<L && ldist[v]==Pre[dist[v]+1]) ans+=used[L-dist[v]-1];
    }
    for(int i=0; i<r; i++)
        used[dist[que[i]]]=0;
    return ans;
}

int dfs(int u)
{
    fa[u]=0;dist[u]=0;
    ldist[u]=c[u-1];rdist[u]=0;
    vis[u]=true;
    int ans=0;
    ans+=go(u);
    for(int i=head[u]; ~i; i=e[i].next)
    {
        int v=e[i].to;
        if(vis[v])  continue;
        ans-=go(v);
    }
    if(ans>0)   return ans;
    for(int i=head[u]; ~i; i=e[i].next)
    {
        int v=e[i].to;
        if(vis[v])  continue;
        get_siz(v);
        tot_size=sz[v];root=0;
        get_root(v,-1,root);
        ans+=dfs(root);
        if(ans>0)   return ans;
    }
    return ans;
}

int main()
{
    freopen("data.txt","r",stdin);
    B[0]=1;
    for(int i=1; i<MAXN; i++)B[i]=B[i-1]*base;
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        read(n);
        init();
        for(int i=1,u,v; i<n; i++)
        {
            read(u);read(v);
            addedge(u,v);
            addedge(v,u);
        }
        scanf("%s %s",c,str);
        Pre[0]=0;Suf[0]=0;
        L=strlen(str);
        for(int i=0; i<L; i++)  Pre[i+1]=Pre[i]*base+str[i];
        reverse(str,str+L);
        for(int i=0; i<L; i++)  Suf[i+1]=Suf[i]*base+str[i];
        get_siz(1);
        tot_size=sz[1];root=0;
        get_root(1,-1,root);
        int ans=dfs(root);
        printf("Case #%d: ",cas++);
        if(ans) puts("Find");
        else puts("Impossible");
    }
    return 0;
}


我更加推崇的树分治方式。

#include<bits/stdc++.h>
#define MAXN 10005
using namespace std;
template<class T>
inline bool read(T &n){
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
typedef unsigned long long LL;
const LL base = 31;
struct edge{
    int to,next;
}E[MAXN*2];
char C[MAXN],S[MAXN];
int head[MAXN],si,fa[MAXN],sz[MAXN],que[MAXN],N,vis[MAXN],dist[MAXN],used[MAXN],L;
LL ldist[MAXN],rdist[MAXN],B[MAXN],Pre[MAXN],Suf[MAXN];
void add_edge(int u,int v)
{
    E[si].to=v;
    E[si].next=head[u];
    head[u]=si++;
}
int get_root(int root)
{
    int l=0,r=0,res=N+1;fa[root]=0;
    for(que[r++]=root;l<r;l++){
        int now=que[l];
        for(int i=head[now];~i;i=E[i].next){
            int u=E[i].to;
            if(vis[u]||fa[now]==u)continue;
            fa[u]=now;
            que[r++]=u;
        }
    }
    for(;r;r--){
        int now=que[r-1], m=0;
        sz[now]=1;
        for(int i=head[now];~i;i=E[i].next){
            int u=E[i].to;
            if(vis[u]||fa[now]==u)continue;
            sz[now]+=sz[u];
            m=max(m,sz[u]);
        }
        m=max(m,l-sz[now]);
        if(res>m){
            res=m;
            root=now;
        }
    }
    return root;
}
int go(int v,int root)
{
    int l=0,r=0;
    int ans=0;
   // printf("go(%d,%d):",v,root);
    for(que[r++]=v;l<r;l++){
        int now=que[l];
        if(dist[now]<L&&rdist[now]==Suf[dist[now]]){
            used[dist[now]]++;
        }
       // printf("dist[%d]=%d___%llu__%llu\n",now,dist[now],ldist[now],rdist[now]);
        for(int i=head[now];~i;i=E[i].next){
            int u=E[i].to;
            if(vis[u]||fa[now]==u)continue;
            fa[u]=now;
            dist[u]=dist[now]+1;
            ldist[u]=ldist[now]+C[u-1]*B[dist[u]];
            rdist[u]=rdist[now]+C[u-1]*B[dist[u]-1];
            que[r++]=u;
        }
    }
    for(int i=0;i<r;i++){
        int u=que[i];
        if(dist[u]<L&&ldist[u]==Pre[dist[u]+1])ans+=used[L-dist[u]-1];
    }
    for(int i=0;i<r;i++){
        int u=que[i];
        used[dist[u]]=0;
    }
   // printf("___%d\n",ans);
    return ans;
}
int solve(int root)
{
    root=get_root(root);fa[root]=0;
  //  printf("root:%d__\n",root);
    dist[root]=0;ldist[root]=C[root-1];rdist[root]=0;vis[root]=true;
    int ans=0;
    ans+=go(root,root);
    for(int i=head[root];~i;i=E[i].next){
        int u=E[i].to;
        if(vis[u])continue;
        ans-=go(u,root);
    }
  //  printf("_____%d\n",ans);
    if(ans>0)return ans;
    for(int i=head[root];~i;i=E[i].next){
        int u=E[i].to;
        if(vis[u])continue;
        ans+=solve(u);
        if(ans>0)return ans;
    }
    return ans;
}
int main()
{
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    B[0]=1;
    for(int i=1;i<MAXN;i++)B[i]=B[i-1]*base;
    int T;scanf("%d",&T);
    for(int cas=1;cas<=T;cas++){
        read(N);
        for(int i=0;i<=N;i++){
            vis[i]=used[i]=0;
            head[i]=-1;
        }
        si=0;
        for(int i=1,u,v;i<N;i++){
            read(u);
            read(v);
            add_edge(u,v);
            add_edge(v,u);
        }
        scanf("%s%s",C,S);
        Pre[0]=0;
        Suf[0]=0;
        L=strlen(S);
        for(int i=0;i<L;i++)Pre[i+1]=Pre[i]*base+S[i];
        reverse(S,S+L);
        for(int i=0;i<L;i++)Suf[i+1]=Suf[i]*base+S[i];
      //  printf("target:%llu")
        int ans=solve(1);
        printf("Case #%d: ",cas);
      //  printf("___%d\n",ans);
        if(ans){
            puts("Find");
        }
        else puts("Impossible");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值