「HNOI2014」抄卡组 题解

题目简介

给你 \(N\) 个字符串,字符串中 * 可以匹配任意数量的任意字符,问这 \(N\) 个字符串是否完全相等。

\(T\) 组询问。

\(N\le 100000,\ T\le 10,\ N\times \max\{\mbox{string.lenth}\}\le2\times 10^8\)

输入文件不超过 \(\mbox{10MB}\)

分析

对于这 \(T\) 个字符串,共 \(3\) 种情况。

  • 全部都有 *
  • 全部没有 *
  • 部分有 *,部分没有 *

现在进行讨论:

  • 全部都有 *

只需要比较所有的前缀(这里指第一个 * 之前的字符)是否相等或包含,以及所有的后缀(这里指最后一个 * 之后的字符)是否相等或包含。因为中间部分可以通过 * 来自动匹配。

  • 全部没有 *

只需要比较所有的字符串是否相等。

  • 部分有 *,部分没有 *

比较有的和没有的之间能否相互匹配。假设每个字符串的前后都有 *,只需要对于两个 * 之间的字符,查看原字符串中是否有与其匹配的。

在实际写的过程中,可以将第一类作为一种情况,比较前缀后缀;将第二种作为一种情况,找到一个没有 * 的字符串,检查其能否与其他字符串匹配。

数据范围巨大,使用 vectorstring

注意关闭输入输出流:

ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);

\(AC\ Code\)

#include<algorithm>
#include<cstdio>
#include<iostream>
#include<string>
#include<vector>
using namespace std;
using ull=unsigned long long;
const int Maxn=1e5+5;
const int Maxm=1e7+5;
const int Pri=1789;
vector<ull>P(Maxm);
string s[Maxn],t[Maxn];
bool hav[Maxn];
vector<ull>h[Maxn];
vector<int>pos[Maxn];
inline ull gethash(int x,int l,int r){return h[x][r+1]-h[x][l]*P[r-l+1];}
void calc(int x){
    h[x].clear();pos[x].clear();
    h[x].emplace_back(0);
    pos[x].emplace_back(-1);
    hav[x]=false;
    for(auto it=s[x].begin();it!=s[x].end();++it){
        h[x].emplace_back(h[x].back()*Pri+*it);
        if(*it=='*'){
            pos[x].emplace_back(it-s[x].begin());
            hav[x]=true;
        }
    }
    pos[x].emplace_back(s[x].length());
}
bool check(int x,int y){
    if(!hav[x]&&!hav[y])return gethash(x,0,s[x].length()-1)==gethash(y,0,s[y].length()-1);
    int p=0;
    for(int i=1;i<pos[x].size();++i){
        int tmp=p,len=pos[x][i]-pos[x][i-1]-1;
        while(tmp+len-1<s[y].length()&&gethash(x,pos[x][i-1]+1,pos[x][i]-1)!=gethash(y,tmp,tmp+len-1))++tmp;
        if(tmp+len-1>=s[y].length())return false;
        if(tmp&&!p)return false;
        p=tmp+len;
    }
    return true;
}
bool cmp(const string &fir,const string &sec){return fir.length()<sec.length();}
bool solve(int n){
    int p=0;
    for(int i=1;i<=n;++i)
        if(!hav[i]){p=i;break;}
    if(!p){
        for(int i=1;i<=n;++i){
            t[i]="";
            for(int j=0;j<s[i].length()&&s[i][j]!='*';++j)t[i]+=s[i][j];
        }
        sort(t+1,t+n+1,cmp);
        for(int i=2;i<=n;++i)
            for(int j=0;j<t[i-1].length();++j)
                if(t[i][j]!=t[i-1][j])return false;
        for(int i=1;i<=n;++i){
            t[i]="";
            for(int j=s[i].length()-1;~j&&s[i][j]!='*';--j)t[i]+=s[i][j];
        }
        sort(t+1,t+n+1,cmp);
        for(int i=2;i<=n;++i)
            for(int j=0;j<t[i-1].length();++j)
                if(t[i][j]!=t[i-1][j])return false;
    }else for(int i=1;i<=n;++i){
        if(i==p)continue;
        if(!check(i,p))return false;
    }
    return true;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int T;cin>>T;
    P[0]=1;
    for(int i=1;i<=1e7;++i)P[i]=P[i-1]*Pri;
    while(T--){
        int n;cin>>n;
        for(int i=1;i<=n;++i)cin>>s[i],calc(i);
        cout<<(solve(n)?"Y":"N")<<'\n';
    }
    return 0;
}

$$-----EOF-----$$

posted @ 2022-07-05 13:36  AlienCollapsar  阅读(39)  评论(0编辑  收藏  举报
// 生成目录索引列表 // ref: http://www.cnblogs.com/wangqiguo/p/4355032.html // modified by: zzq