题目
题目链接: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,mleq 10^5;kleq 4)。
思路
挺无聊的一道缝合题。。。
发现 (kleq 4),也就是每一个字符串 (s_i) 最多只有 (16) 个模式串 (p) 可以匹配上。所以我们可以把每一个模式串标号,对于每一个字符串枚举所有能和它匹配的模式串,要求这些模式串的编号都必须大于 (mt_i) 的编号。
那就直接上拓扑排序即可。匹配可以不用 Tire,直接看成一个 27 进制数用数组存即可。(27^4leq 6 imes 10^5)。
时间复杂度 (O(2^knk))。
代码
#include <bits/stdc++.h>
#define pYES printf("YES
");
#define pYes printf("Yes
");
#define pyes printf("yes
");
#define pNO printf("NO
");
#define pNo printf("No
");
#define pno printf("no
");
#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;
}