【CF1476E】Pattern Matching

题目

题目链接:https://codeforces.com/problemset/problem/1476/E
给定 \(n\) 个模式串 \(p_i\)\(m\) 个字符串 \(s_i\),其中 \(p_i\) 两两不同。每个模式串和字符串都包含 \(k\) 个字符。其中模式串中可以含通配符(用下划线表示,可以匹配任何字符),剩余字符都为小写英文字母。同时给定 \(n\) 个数 \(mt_i\),要求重新排列模式串使得 \(s_j\) 匹配到的第一个模式串为 \(p_{mt_j}\)。请判断是否存在排列方案满足如上要求,能的话请输出方案。
\(n,m\leq 10^5;k\leq 4\)

思路

挺无聊的一道缝合题。。。
发现 \(k\leq 4\),也就是每一个字符串 \(s_i\) 最多只有 \(16\) 个模式串 \(p\) 可以匹配上。所以我们可以把每一个模式串标号,对于每一个字符串枚举所有能和它匹配的模式串,要求这些模式串的编号都必须大于 \(mt_i\) 的编号。
那就直接上拓扑排序即可。匹配可以不用 Tire,直接看成一个 27 进制数用数组存即可。\(27^4\leq 6\times 10^5\)
时间复杂度 \(O(2^knk)\)

代码

#include <bits/stdc++.h>
#define pYES printf("YES\n");
#define pYes printf("Yes\n");
#define pyes printf("yes\n");
#define pNO printf("NO\n");
#define pNo printf("No\n");
#define pno printf("no\n");
#define mp make_pair
#define ST first
#define ND second
using namespace std;
typedef long long ll;
typedef long double ld;

const int N=100010,M=600010;
int n,m,k,tot,head[N],id[M],deg[N],ans[N];
char s[N][6],t[6];

struct edge
{
	int next,to;
}e[N*16];

void add(int from,int to)
{
	e[++tot]=(edge){head[from],to};
	head[from]=tot; deg[to]++;
}

void topsort()
{
	tot=0;
	queue<int> q;
	for (int i=1;i<=n;i++)
		if (!deg[i]) q.push(i);
	while (q.size())
	{
		int u=q.front(); q.pop();
		ans[++tot]=u;
		for (int i=head[u];~i;i=e[i].next)
		{
			int v=e[i].to;
			deg[v]--;
			if (!deg[v]) q.push(v);
		}
	}
}

int main()
{
	memset(head,-1,sizeof(head));
	scanf("%d%d%d",&n,&m,&k);
	for (int i=1;i<=n;i++)
	{
		scanf("%s",s[i]+1);
		int p=0;
		for (int j=1;j<=k;j++)
			p=p*27+((s[i][j]=='_')?0:(s[i][j]-'a'+1));
		id[p]=i;
	}
	for (int i=1,x;i<=m;i++)
	{
		scanf("%s",t+1);
		scanf("%d",&x);
		int q=0;
		for (int j=1;j<=k;j++)
			q=q*27+((s[x][j]=='_')?0:(s[x][j]-'a'+1));
		bool flag=0;
		for (int j=0;j<(1<<k);j++)
		{
			int p=0;
			for (int l=1;l<=k;l++)
				p=p*27+((j&(1<<(l-1)))?0:(t[l]-'a'+1));
			if (id[p] && p!=q) add(id[q],id[p]);
				else if (p==q) flag=1;
		}
		if (!flag)  { pNO; return 0; }
	}
	topsort();
	if (tot<n) { pNO; return 0; }
	pYES; 
	for (int i=1;i<=n;i++)
		printf("%d ",ans[i]);
	return 0;
}
posted @ 2021-05-14 20:46  stoorz  阅读(36)  评论(0编辑  收藏  举报