题目简介:
# 于是他错误的点名开始了
## 题目背景
XS中学化学竞赛组教练是一个酷爱炉石的人。
他会一边搓炉石一边点名以至于有一天他连续点到了某个同学两次,然后正好被路过的校长发现了然后就是一顿欧拉欧拉欧拉(详情请见已结束比赛 CON900)。
## 题目描述
这之后校长任命你为特派探员,每天记录他的点名。校长会提供化学竞赛学生的人数和名单,而你需要告诉校长他有没有点错名。(为什么不直接不让他玩炉石。)
## 输入格式
第一行一个整数 $n$,表示班上人数。
接下来 $n$ 行,每行一个字符串表示其名字(互不相同,且只含小写字母,长度不超过 $50$)。
第 $n+2$ 行一个整数 $m$,表示教练报的名字个数。
接下来 $m$ 行,每行一个字符串表示教练报的名字(只含小写字母,且长度不超过 $50$)。
## 输出格式
对于每个教练报的名字,输出一行。
如果该名字正确且是第一次出现,输出 `OK`,如果该名字错误,输出 `WRONG`,如果该名字正确但不是第一次出现,输出 `REPEAT`。
## 样例 #1
### 样例输入 #1
```
5
a
b
c
ad
acd
3
a
a
e
```
### 样例输出 #1
```
OK
REPEAT
WRONG
```
## 提示
- 对于 $40\%$ 的数据,$n\le 1000$,$m\le 2000$。
- 对于 $70\%$ 的数据,$n\le 10^4$,$m\le 2\times 10^4$。
- 对于 $100\%$ 的数据,$n\le 10^4$,$m≤10^5$。
---
$\text{upd 2022.7.30}$:新增加一组 Hack 数据。
题目本质:字符串,搜索,字典树,Trie。
暴力法(尽力70分):
#include<bits/stdc++.h>
using namespace std;
const int N=10005;
struct student{
string name1;
bool get;
}stu[N];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
cin>>stu[i].name1;
stu[i].get=true;
}
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++){
string name2;
bool judge=false;
cin>>name2;
for(int j=1;j<=n;j++){
if(name2==stu[j].name1 && stu[j].get==false){
cout<<"REPEAT"<<endl;
judge=true;
}
if(name2==stu[j].name1 && stu[j].get==true){
cout<<"OK"<<endl;
judge=true;
stu[j].get=false;
}
}
if(judge==false){
cout<<"WRONG"<<endl;
}
}
return 0;
}
题目思路:
从图中可以直观看出,从左到右扫这个单词,如果字母在相应根节点下没有出现过,就插入这个字母;否则沿着字典树往下走,看单词的下一个字母。给每个字母编号。
我们设数组trie[i][j]=k,表示编号为i的节点的第j个孩子是编号为k的节点。
这里有2种编号,一种是i,k表示节点的位置编号,这是相对整棵树而言的;另一种是j,表示节点i的第j的孩子,这是相对节点i而言的。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
string a[N];
bool k[N];
int n,m;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
cin>>m;
for(int i=1;i<=m;i++){
bool oo=0;
string b;
cin>>b;
for(int j=1;j<=n;j++){
if(b==a[j]&&k[j]==0) {
cout<<"OK"<<endl;
k[j]=1;
oo=1;
break;
}
else if(b==a[j]&&k[j]==1){
cout<<"REPEAT"<<endl;
oo=1;
break;
}
}
if(oo==0){
cout<<"WRONG"<<endl;
}
}
return 0;
}