bzoj4598 [Sdoi2016]模式字符串 hash+点分

哈希也是有技巧的。不然很容易错。

匹配串范围是1e6的,所以普通hash错误概率也是很大的

所以就要利用匹配的特性(长度与匹配串一一对应)来hash,这样错误概率会小,相当于hash挂链吧。

一开始写的每个前缀hash存位置。这样一个hash里就有1e6个值。


码:

#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<cstring>
#define P 2147483647
#define ll long long 
#define D(x) cout<<x<<" ";
using namespace std;
#define N 2000005
#define ll long long
vector<int>v[N];
ll qian[N],hou[N];
int sz[N],fu[N],f[N],g[N],vf[N],vg[N],i,j,n,m,ans,tot,rt,now,T,a,b;
ll ci[N],lin;
char  ch[N],S[N];
bool vis[N];
void dfs(int o,int fa)
{
int i,nd;
    sz[o]=1;fu[o]=fa;
    for(i=0;i<v[o].size();i++)
    {
        nd=v[o][i];
        if(nd==fa||vis[nd])continue;dfs(nd,o);
        sz[o]+=sz[nd];
    }       
}
void zzx(int o,int qsz)
{
    int szcnt=0,i,nd,maxx=qsz;
    for(i=0;i<v[o].size();i++)
    if(vis[v[o][i]]==0&&fu[o]!=v[o][i])szcnt+=sz[v[o][i]],maxx=max(maxx,sz[v[o][i]]);
    if(maxx<=tot/2)rt=o; 
    for(i=0;i<v[o].size();i++)
    {   
    nd=v[o][i];
    if(nd==fu[o]||vis[nd])continue;
    zzx(nd,qsz+1+szcnt-sz[nd]);     
    }   
}
void Dfs(int o,int fa,ll lin,int dis)
{
    int i,nd;
    if(qian[dis]==lin&&vg[m-dis%m-1]==now)  //统计答案 
    ans+=g[m-dis%m-1];  
    if(hou[dis]==lin&&vf[m-dis%m-1]==now)   //统计答案 
    ans+=f[m-dis%m-1];   
     
    for(i=0;i<v[o].size();i++)
    {
        nd=v[o][i];
        if(nd==fa||vis[nd])continue;
        Dfs(nd,o,(lin+(1ll*(ch[nd]-'A'+1)*ci[dis+1])%P)%P,dis+1);
    }
}
void dfS(int o,int fa,ll lin,int dis)
{
    int i,nd;
    if(qian[dis]==lin)  //统计答案 
    {
    if(vf[dis%m]!=now)vf[dis%m]=now,f[dis%m]=0; 
    f[dis%m]++; 
    }
    if(hou[dis]==lin)   //统计答案 
    {
    if(vg[dis%m]!=now)vg[dis%m]=now,g[dis%m]=0;     
    g[dis%m]++; 
    }
    for(i=0;i<v[o].size();i++)
    {
        nd=v[o][i];
        if(nd==fa||vis[nd])continue;
        dfS(nd,o,(lin+(1ll*(ch[nd]-'A'+1)*ci[dis+1])%P)%P,dis+1);
    }
}
void solve(int o)
{
    now=o;
    int i,nd,hx=ch[o]-'A'+1;
if(qian[0]==hx)vf[0]=o,f[0]=1;
if(hou[0]==hx)vg[0]=o,g[0]=1;
if(vf[0]==o&&vf[0]==vg[m-1])
ans+=g[m-1];
    for(i=0;i<v[o].size();i++)
    {
        nd=v[o][i];
        if(vis[nd])continue;
        Dfs(nd,o,(hx+(ch[nd]-'A'+1)*ci[1])%P,1);
        dfS(nd,o,(hx+(ch[nd]-'A'+1)*ci[1])%P,1);    
    }
}
void work(int o)
{
    vis[o]=1;
    solve(o);
    int i,nd;
    for(i=0;i<v[o].size();i++)
    {
        nd=v[o][i]; 
        if(vis[nd]||sz[nd]<m)continue;   
tot=sz[nd]; dfs(nd,o);zzx(nd,0);   dfs(rt,0);
work(rt);   
    }
}
int main()
{
    ci[0]=1;
    for(i=1;i<=100000;i++)ci[i]=(ci[i-1]*27)%P;
    scanf("%d",&T);
    while(T--)
    {ans=0;
        memset(vf,0,sizeof(vf));
        memset(vg,0,sizeof(vg));    
        memset(vis,0,sizeof(vis));
        for(i=1;i<=100000;i++)
        v[i].clear();
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)
        {
        scanf("%c",&ch[i]);
        while(ch[i]<'A'||ch[i]>'Z')scanf("%c",&ch[i]);
        }
        for(i=1;i<n;i++)
        {
            scanf("%d%d",&a,&b);
            v[a].push_back(b);
            v[b].push_back(a);
        }
        for(i=1;i<=m;i++)
        {
        scanf("%c",&S[i]);while(S[i]<'A'||S[i]>'Z')scanf("%c",&S[i]);
        }
lin=0;
for(i=0;i<=n;i++)
{
        lin=(lin*27+1ll*(S[(i%m)+1]-'A'+1))%P;
        qian[i]=lin;    
}
lin=0;
for(i=0;i<=n;i++)
{
        lin=(lin*27+1ll*(S[(m-i%m-1)+1]-'A'+1))%P;
        hou[i]=lin;
}       
        dfs(1,0);
        tot=n;
        zzx(1,0);   dfs(rt,0);
        work(rt);   printf("%d\n",ans); 
    }
}

猜你喜欢

转载自blog.csdn.net/haobang866/article/details/79453271