题意
有n个模式串与m个字符串,长度均为k。要求重新排序模式串使得第
i
i
i个字符串依次匹配模式串,第一个被匹配的模式串排序前编号为
m
t
i
mt_i
mti。
字符串均由小写字母组成,模式串由小写字母和下划线组成,下划线可以和任意字母匹配。
问:是否存在一种排序方式满足要求,若能则输出任意一种方式。
数据范围
1
≤
n
≤
1
0
5
1\leq n\leq 10^5
1≤n≤105
1
≤
m
≤
1
0
5
1\leq m\leq 10^5
1≤m≤105
1
≤
k
≤
4
1\leq k\leq 4
1≤k≤4
1
≤
m
t
i
≤
n
1\leq mt_i\leq n
1≤mti≤n
题解
很显然可以发现,第j个字符串若不能与
m
t
j
mt_j
mtj匹配,直接输出"NO",否则,若可以和
m
t
j
,
x
1
,
x
2
,
.
.
.
mt_j,x_1,x_2,...
mtj,x1,x2,...进行匹配,在新排列的模式串中,
x
1
,
x
2
.
.
.
x_1,x_2...
x1,x2...要放在
m
t
j
mt_j
mtj后面,即可以用
m
t
j
mt_j
mtj向
x
1
,
x
2
.
.
.
x_1,x_2...
x1,x2...连边。
最终即可得到一个图。要想存在一种排序方式,该图一定要是一个有向无环图,要想得到一种排序方式,直接拓扑排序扫一下即可。
以上部分我比赛时也想到了,结果不知道怎么快速进行匹配。
注意到k最大只有4,我们可以将一个字符串(不是模式串)拆成
2
k
2^k
2k种情况,即枚举位置将部分字母替换成下划线,再将
2
k
2^k
2k个字符串放入模式串建的字典树里去跑。即可在
O
(
2
k
k
)
O(2^k k)
O(2kk)完成匹配。
这题我一直在想如何处理模式串的下划线,没有转换思维用下划线替换字符串中的字母。
由于每个点最多只能连15条边,所以建图不用担心内存不够。时间复杂度为
O
(
n
k
+
m
k
2
k
)
O(nk+mk2^k)
O(nk+mk2k)。
代码
/*************************************************************************
> File Name: 1.cpp
> Author: Knowledge_llz
> Mail: 925538513@qq.com
> Blog: https: https://www.cnblogs.com/Knowledge-Pig/
> Created Time: 2021/2/1 15:25:34
************************************************************************/
#include<bits/stdc++.h>
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define LL long long
#define pb push_back
#define fi first
#define se second
#define pr pair<int,int>
#define mk(a,b) make_pair(a,b)
using namespace std;
int read(){
char x=getchar(); int u=0,fg=0;
while(!isdigit(x)){ if(x=='-') fg=1; x=getchar(); }
while(isdigit(x)){ u=(u<<3)+(u<<1)+(x^48); x=getchar(); }
return fg?-u:u;
}
const int maxx=2e5+10;
int n,m,k;
char tmp[5];
struct Trie{
int ch[maxx][30];
int val[maxx];
int sz;
Trie(){ sz=1; memset(ch[0],0,sizeof(ch[0])); }
int idx(char c){
if(c!='_') return c-'a';
else return 26;
}
void insert(char *s,int v){
int u=0;
For(i,0,k-1){
int c=idx(s[i]);
if(!ch[u][c]){
memset(ch[sz],0,sizeof(ch[sz]));
ch[u][c]=sz++;
}
u=ch[u][c];
}
val[u]=v;
}
int query(char *s,int mode){
int u=0;
For(i,0,k-1){
int c=idx(s[i]);
if(mode&1) c=26;
mode>>=1;
u=ch[u][c];
}
return val[u];
}
}trie;
vector<int>vec[maxx],ans;
int d[maxx];
bool vis[maxx];
void dfs(int id){
ans.pb(id);
vis[id]=1;
for(auto i:vec[id]){
--d[i];
if(!d[i]) dfs(i);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
freopen("output.out", "w", stdout);
#endif
n=read(); m=read(); k=read();
For(i,1,n){
scanf("%s",tmp);
trie.insert(tmp,i);
}
For(i,1,m){
int mt; bool flag=0;
scanf("%s%d",tmp,&mt);
For(i,0,15){
int u=trie.query(tmp,i);
if(!u) continue;
if(u!=mt){ vec[mt].pb(u); ++d[u]; }
else flag=1;
}
if(!flag){ printf("NO\n"); return 0; }
}
For(i,1,n) if(!d[i] && !vis[i]) dfs(i);
if(ans.size()!=n) printf("NO\n");
else{
printf("YES\n");
for(auto i:ans) printf("%d ",i);
}
return 0;
}