「HNOI2014」抄卡组 题解
题目简介
给你 \(N\) 个字符串,字符串中 *
可以匹配任意数量的任意字符,问这 \(N\) 个字符串是否完全相等。
共 \(T\) 组询问。
\(N\le 100000,\ T\le 10,\ N\times \max\{\mbox{string.lenth}\}\le2\times 10^8\)
输入文件不超过 \(\mbox{10MB}\)。
分析
对于这 \(T\) 个字符串,共 \(3\) 种情况。
- 全部都有
*
- 全部没有
*
- 部分有
*
,部分没有*
现在进行讨论:
- 全部都有
*
只需要比较所有的前缀(这里指第一个 *
之前的字符)是否相等或包含,以及所有的后缀(这里指最后一个 *
之后的字符)是否相等或包含。因为中间部分可以通过 *
来自动匹配。
- 全部没有
*
只需要比较所有的字符串是否相等。
- 部分有
*
,部分没有*
比较有的和没有的之间能否相互匹配。假设每个字符串的前后都有 *
,只需要对于两个 *
之间的字符,查看原字符串中是否有与其匹配的。
在实际写的过程中,可以将第一类作为一种情况,比较前缀后缀;将第二种作为一种情况,找到一个没有 *
的字符串,检查其能否与其他字符串匹配。
数据范围巨大,使用 vector
和 string
注意关闭输入输出流:
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;
}