Educational Codeforces Round 103 E题 Pattern Matching (字典树+拓扑排序)

传送门

题意

有n个模式串与m个字符串,长度均为k。要求重新排序模式串使得第(i)个字符串依次匹配模式串,第一个被匹配的模式串排序前编号为(mt_i)
字符串均由小写字母组成,模式串由小写字母和下划线组成,下划线可以和任意字母匹配。
问:是否存在一种排序方式满足要求,若能则输出任意一种方式。

数据范围

[1leq nleq 10^5 ]

[1leq mleq 10^5 ]

[1leq kleq 4 ]

[1leq mt_ileq n ]

题解

很显然可以发现,第j个字符串若不能与(mt_j)匹配,直接输出"NO",否则,若可以和(mt_j,x_1,x_2,...)进行匹配,在新排列的模式串中,(x_1,x_2...)要放在(mt_j)后面,即可以用(mt_j)(x_1,x_2...)连边。
最终即可得到一个图。要想存在一种排序方式,该图一定要是一个有向无环图,要想得到一种排序方式,直接拓扑排序扫一下即可。
以上部分我比赛时也想到了,结果不知道怎么快速进行匹配。
注意到k最大只有4,我们可以将一个字符串(不是模式串)拆成(2^k)种情况,即枚举位置将部分字母替换成下划线,再将(2^k)个字符串放入模式串建的字典树里去跑。即可在(O(2^k k))完成匹配。
这题我一直在想如何处理模式串的下划线,没有转换思维用下划线替换字符串中的字母。
由于每个点最多只能连15条边,所以建图不用担心内存不够。时间复杂度为(O(nk+mk2^k))

代码

/*************************************************************************
	> 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
"); return 0; }
	}
	For(i,1,n) if(!d[i] && !vis[i])  dfs(i);
	if(ans.size()!=n) printf("NO
");
	else{
		printf("YES
");
		for(auto i:ans) printf("%d ",i);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Knowledge-Pig/p/14357263.html