A - ZJM 与霍格沃兹
题目
样例输入
[expelliarmus] the disarming charm
[rictusempra] send a jet of silver light to hit the enemy
[tarantallegra] control the movement of one's legs
[serpensortia] shoot a snake out of the end of one's wand
[lumos] light the wand
[obliviate] the memory charm
[expecto patronum] send a Patronus to the dementors
[accio] the summoning charm
@END@
4
[lumos]
the summoning charm
[arha]
take me to the sky
样例输出
light the wand
accio
what?
what?
思路
申请两个字符串数组,分别存储魔咒和对应功能。
申请map,计算出魔咒或者对应功能的Hash值,将Hash值作为key,索引作为value。
在查找魔咒对应的功能或者功能对应魔咒的时候,计算出查询使用魔咒或者对应功能的Hash值,然后通过map寻找对应功能或者魔咒。
为什么不使用map直接存储字符串呢,因为魔咒对应功能与功能对应魔咒,需要两个map,意味着要多将魔咒和功能进行一次存储。会使用更多空间。
代码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<map>
#include<cstring>
using namespace std;
map<int, int> en;
map<int, int> trans;
char e[100010][25], t[100010][85];
int Hash(char* s)
{
int seed = 17;
int seedd = 17;
int m = 1e9 + 7;
int n = strlen(s);
int h = 0;
for (int i = 0; i < n; i++)
{
h = (h + seedd * s[i]) % m;
seedd = (seedd * seed) % m;
}
return h;
}
int main()
{
char c[25];
char cc[85];
int k = 0;
while (1)
{
cin.ignore(1);
int i = 0;
while (1)
{
char ccc;
ccc = getchar();
if (ccc == '@' || ccc == ']') break;
//cout << ccc << endl;
c[i++] = ccc;
}
c[i] = '\0';
if (!strcmp(c, "END")) break;
cin.ignore(1);
cin.getline(cc, 85, '\n');
//cout << c << "!!!!!!" << cc << endl;
strcpy(e[k], c);
en[Hash(c)] = k;
trans[Hash(cc)] = k;
strcpy(t[k], cc);
k++;
}
int n;
cin >> n;
cin.ignore();
for (int j = 0; j < n; j++)
{
cin.getline(cc, 85);
if (cc[0] == '[')//魔咒
{
for (int i = 1; i < strlen(cc); i++)
c[i - 1] = cc[i];
c[strlen(cc) - 2] = '\0';
//cout << "???" << c << endl;
int h = Hash(c);
if (en.count(h) == 0) cout << "what?" << endl;
else cout << t[en[h]] << endl;
}
else
{
int h = Hash(cc);
if(trans.count(h) == 0) cout << "what?" << endl;
else cout << e[trans[h]] << endl;
}
}
//system("pause");
}
B - ZJM 与生日礼物
题目
样例输入
01
10
0010
0000
9
01
10
010
0000
9
样例输出
Set 1 is immediately decodable
Set 2 is not immediately decodable
思路
因为只需要查找一个串是不是另一个串的前缀,因此在插入的过程中就可以进行查找。
插入的时候,如果过程中遇到插入的某一位flag = 1,说明已经存在的一个串是另一个串的前缀;如果插入到最后一个字符,插入位置已经存在的时候,说明插入的串是某一个已经存在的串的子串。
代码
#include<iostream>
#include<cstring>
using namespace std;
struct tree
{
static const int N = 1010, chaset=2;
int root, tot, flag[N], child[N][chaset];
tree()
{
tot = root = 0;
//memset(flag, 0, sizeof flag);
memset(child, -1, sizeof child);
}
void clear()
{
tot = 0;
memset(child, -1, sizeof child);
}
bool insert(char* c)
{
int now = root;
int n = strlen(c);
for (int i = 0; i < n; i++)
{
int x = c[i] - '0';
if (child[now][x] == -1)
{
child[now][x] = ++tot;
flag[now] = 0;
}
else if (i == n - 1 || flag[child[now][x]] == 1) return true;
now = child[now][x];
}
flag[now] = 1;
return false;
}
};
int main()
{
char c[120];
int k = 1;
while (cin >> c)
{
bool is = 0;
tree t;
if (t.insert(c)) is = 1;
while (1)
{
cin >> c;
if (!strcmp(c, "9")) break;
if (t.insert(c)) is = 1;
}
if (is) cout << "Set "<< k << " is not immediately decodable" << endl;
else cout << "Set " << k << " is immediately decodable" << endl;
k++;
}
}
C - ZJM 与纸条
题目
样例输入
3
BAPC
BAPC
AZA
AZAZAZA
VERDI
AVERDXIVYERDIAN
样例输出
1
3
0
思路
就是一个kmp算法,需要统计每一行出现多少次。
可以采用每一次查找一个模式串,然后从查找到位置的后一个位置继续查找,直到主串的末尾。
但是效率低且麻烦。
因此可以考虑next数组多加一个位置,计算如果模式串被匹配,前缀的长度。一旦模式串被匹配,j指针可以直接进行移动。
ps:学kmp算法的时候把我点通的视频链接
https://www.bilibili.com/video/BV1jb411V78H?from=search&seid=15026284555623424799
https://www.bilibili.com/video/BV1i64y1M7zv?t=676
代码
#include<iostream>
using namespace std;
int* getNext(char* p)
{
int n = strlen(p);
int *next = new int[n + 1];
next[0] = -1;
int j = 0, k = -1;
while (j < n) {
if(k >= 0 && p[j] != p[k]) k = next[k];
else next[++j] = ++k;
}
return next;
}
int kmp(char* m, char* p)
{
int *next = getNext(p);
int msize = strlen(m);
int psize = strlen(p);
int i = 0, j = 0, num = 0;
while (1)
{
if (i == msize) {
if (j == psize) num++;
break;
}
else if (j == psize) num++, j = next[j];
else if(j == -1 || m[i] == p[j]) i++, j++;
else j = next[j];
}
return num;
}
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
char p[10010], m[1000010];
cin >> p;
cin >> m;
cout << kmp(m, p) << endl;
}
//system("Pause");
}