不太理解题意的可以上 CodeForces 看原版英文题面:Link

上面也有英文原版题解。

首先我们直接令 $g = 9$ 即可,因为 r 最多只有 $9$ 个,而翻完就会自动停止。

接着我们考虑转化一下问题。

首先我们必须翻出所有的 r,并且不能翻出其他的小写字母,对于大写字母翻了也没事。

那么我们可以考虑转化成一个字符串匹配的问题。

对于输入的字符串,我们将它们的所有前缀(取前缀是因为可能翻到某一步就停止了)作为文本串。并将一个字母对应的位置设成 1,其余的设成 0z 不做处理。

例如:azcex 对应 1010100000000000000000010

对于输入的表格,我们将它们作为模式串。具体来说,r 对应 1,其余小写字母对应 0,大写字母对应通配符 ?

例如:rnnnB rnBBb nrBrr RBBrR rxnnb 对应:1000?10??001?11???1?10000

我们的任务是对于每一个模式串找到与之匹配的文本串。

我们考虑这一件事情,设 $cnt_0$,$cnt_1$,$cnt_q$ 分别表示 模式串中为 01? 的数量。

由于平均值原理:

$$
\min(cnt_0,cnt_1,cnt_q) \leq \frac{cnt_0+cnt_1+cnt_q}{3} = \frac{25}{3} \leq 9
$$

所以如果我们有分别与 $cnt_0$,$cnt_1$,$cnt_q$ 相关的算法,我们就可以在较优秀的时间复杂度内解决问题。

与 $cnt_q$ 相关

暴力枚举通配符的取值即可。实现上可以用枚举子集简单实现。

单词操作时间复杂度 $O(2^9)$。

与 $cnt_1$ 相关

我们考虑如何数出一个模式串的与之匹配的文本串。

对于通配符我们并不好处理,由于文本串实际上是二进制数,这启发我们使用高维前缀和,直接令通配符取值 1

但是这样我们模式串中要求为 1 的位就无法达成限制,所以我们考虑容斥掉这一部分。

具体来说,我们把一些为 1 的位设成 0,设这样的位有 $t$ 个,那么容斥系数即为 $(-1)^t$。

容斥可以用枚举子集简单实现。

如果存在这样的文本串,我们还需要考虑如何求出这一个文本串。

我们对于每一个 ? 先将其设为 0 计算对应文本串个数,如果存在,那么这一位填 0,否则这一位填 1

这一部分可以用 Lowbit 简单实现。

单次操作时间复杂度 $O(18 \times 2^9)$

与 $cnt_0$ 相关

与 $cnt_1$ 的部分本质相同,各位可以自行思考,我将修改过的部分写在下面。

我们使用高维后缀和,直接令通配符取值 0

容斥掉要求为 0 的部分。

我们把一些为 0 的位设成 1,设这样的位有 $t$ 个,那么容斥系数即为 $(-1)^t$。

如果存在这样的文本串,我们还需要考虑如何求出这一个文本串。

我们对于每一个 ? 先将其设为 1 计算对应文本串个数,如果存在,那么这一位填 1,否则这一位填 0

其中高维前缀和预处理时间复杂度是 $O(2^{25})$ 的,常数优秀,可以通过本题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5;
const int maxm=30;
const int maxk=25;
const int maxs=1<<maxk;
int n,m;
char str[maxn+5][maxm+5];
int id[maxs+5];
int f[maxs+5],g[maxs+5];
int tmpq,tmp0,tmp1;
int cntq,cnt0,cnt1;
inline char Getch(){
char ch=getchar();
while(!(('a'<=ch&&ch<='z')||('A'<=ch&&ch<='Z')))
ch=getchar();
return ch;
}
inline int Lowbit(int x){return x&(-x);}
inline int Count0(){
int res=0;
for(int s=tmp0;;s=(s-1)&tmp0){
if(__builtin_popcount(s)&1) res-=g[s|tmp1|tmpq];
else res+=g[s|tmp1|tmpq];
if(!s) break;
}
return res;
}
inline int Count1(){
int res=0;
for(int s=tmp1;;s=(s-1)&tmp1){
if((cnt1-__builtin_popcount(s))&1) res-=f[s|tmpq];
else res+=f[s|tmpq];
if(!s) break;
}
return res;
}
signed main(){
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
int len,tmp;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",str[i]);
len=strlen(str[i]),tmp=0;
for(int j=0;j<len;j++){
if(str[i][j]!='z'){
tmp|=1<<(str[i][j]-'a');
id[tmp]=i;
f[tmp]++,g[tmp]++;
}
}
}
for(int i=0;i<maxk;i++){
for(int j=0;j<maxs;j++){
if((j>>i)&1) f[j]+=f[j^(1<<i)];
else g[j]+=g[j^(1<<i)];
}
}
char ch;
int res;
scanf("%d",&m);
while(m--){
tmpq=tmp0=tmp1=0;
cntq=cnt0=cnt1=0;
for(int i=0;i<maxk;i++){
ch=Getch();
if('A'<=ch&&ch<='Z') tmpq|=1<<i,cntq++;
else if(ch=='r') tmp1|=1<<i,cnt1++;
else tmp0|=1<<i,cnt0++;
}
if(cnt0==min({cnt0,cnt1,cntq})){
int s=tmpq;tmpq=0;
if(Count0()){
for(;s;s-=Lowbit(s)){
tmpq+=Lowbit(s);
if(!Count0()) tmpq-=Lowbit(s);
}
res=tmp1|tmpq;
}
else res=-1;
}
else if(cnt1==min({cnt0,cnt1,cntq})){
int s=tmpq;
if(Count1()){
for(;s;s-=Lowbit(s)){
tmpq-=Lowbit(s);
if(!Count1()) tmpq+=Lowbit(s);
}
res=tmp1|tmpq;
}
else res=-1;
}
else{
res=-1;
for(int s=tmpq;;s=(s-1)&tmpq){
if(id[tmp1|s]) res=tmp1|s;
if(!s) break;
}
}
if(~res) printf("%s 9\n",str[id[res]]);
else puts("IMPOSSIBLE");
}
return 0;
}