[BZOJ 4060] Word Equations

Link:

BZOJ 4060 传送门

Solution:

可以发现字符串间的关系可以构成一棵树

于是我们先用字符串哈希建树,再树形$dp$即可

 

设$dp[i][j]$为第$i$个节点从$P$字符串的第$j$为开始匹配的失配位置

则有$dp[i][j]=dp[ch[i][1]][dp[ch[i][0]][j]]$

在叶子节点时暴力匹配就行了,复杂度$O(k*P)$

Code:

#include <bits/stdc++.h>

using namespace std;

const int MAXN=505,ML=2005;
int T,n,hs[MAXN],dp[MAXN][ML],ch[MAXN][2],root;
char S[ML],P[ML],dat[MAXN][ML],tmp[ML],a[ML];

inline int hash(char t[])
{
    int ret=0;
    for(int i=0;i<5;i++)
        ret=ret*27+((i<strlen(t))?(t[i]-'A'+1):0);
    return ret;
}

int dfs(int x,int y)
{
    if(dp[x][y]!=-1) return dp[x][y];
    if(ch[x][0]) return dp[x][y]=dfs(ch[x][1],dfs(ch[x][0],y));
    int k=y;
    for(int cur=0;k<strlen(P) && cur<strlen(dat[x]);cur++)
        if(dat[x][cur]==P[k]) k++;
    return dp[x][y]=k;
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);memset(dp,-1,sizeof(dp));
        for(int i=1;i<=n;i++)
        {
            scanf("%s%s%s",a,tmp,dat[i]);hs[i]=hash(a);
            if(dat[i][0]>='a' && dat[i][0]<='z') ch[i][0]=ch[i][1]=0;
            else
            {
                ch[i][0]=hash(dat[i]);
                scanf("%s%s",tmp,dat[i]);
                ch[i][1]=hash(dat[i]);
            }    
        }
        
        for(int i=1;i<=n;i++) if(ch[i][0])
            for(int j=0;j<2;j++) for(int k=1;k<=n;k++)
                if(ch[i][j]==hs[k]) ch[i][j]=k;
        scanf("%s%s",S,P);
        for(int i=1;i<=n;i++) if(hs[i]==hash(S)) root=i;
        
        printf((dfs(root,0)<strlen(P))?"NO\n":"YES\n");
    }
    return 0;
}

 

Review:

如要对字符数组大量比较+判等于,最好使用字符串$Hash$ (采用27进制)

如果不考虑$string$输入效率较低,则对$string$用$map$或$hash\_ map$更优

 

posted @ 2018-06-30 17:07  NewErA  阅读(269)  评论(0编辑  收藏  举报