一.P2580 于是他错误的点名开始了
这道题也类似于模版题,只要我们熟悉插入和查找的过程,一样可以解决,这里只要注意一下第一次出现和其它次出现所输出是不一样的,这里我们只要在查找函数中返回不同的值,这样就可以解决了。
#include<bits/stdc++.h>
using namespace std;
#define N 1000005
int n, m, id, ans, num;
int f[N][27], cnt[N]; //f数组为建树用,cnt数组记录插入次数
bool vis[N]; //标记数组
char s[N];void insert(char s[]) //插入函数
{int p = 0; //p指针指向根节点for (int i = 0; s[i]; i++) {int q = s[i] - 'a' + 1;if (!f[p][q]) f[p][q] = ++id; //如果没有该节点,就新建一个p = f[p][q]; //继续往下插入}vis[p] = true; //插入完成,为下面查询时做铺垫
}int find(char s[]) //查找函数,注意这里要返回0,1,2三个值代表不同状态
{int p = 0;for (int i = 0; s[i]; i++) {int q = s[i] - 'a' + 1;if (!f[p][q]) return 0; //如果没有查找到该字符,退出p = f[p][q];}if (!vis[p]) return 0; //没有查找到该字符串if (cnt[p]==0) { //找到该字符串,但要讨论是第几次查到++cnt[p];return 1;}return 2;
}
int main()
{memset(vis, false, sizeof(vis));memset(cnt, 0, sizeof(cnt));cin >> n;for (int i = 1; i <= n; i++) {cin >> s;insert(s);}cin >> m;for (int i = 1; i <= m; i++) {cin >> s;int k = find(s);if (k == 0) //如果没有找到cout << "WRONG" << endl;if (k == 1) //如果第一次找到cout << "OK" << endl;if (k == 2) //如果不是第一次找到cout << "REPEAT" << endl;}return 0;
}
二.P1481 魔族密码
对于这题我们只需要进行插入操作就可以,不需要进行查找操作,准确来说应该是在插入过程中进行查询,我们只需要在一个单词的末尾加上一个cnt数组记录插入单词末尾的次数后续的插入如果经过这个单词末尾(也就是能够连接起来),我们加上cnt[p],最后比较出最大的再+1就可以了
#include<bits/stdc++.h>
using namespace std;
#define N 2005
int f[N][27], cnt[N];
char s[N];
int n, m, sum, ans, id;int solve(char s[])
{int p = 0; //p头指针,指向根节点int ans1 = 0;for (int i = 0; s[i]; i++){int q = s[i] - 'a' + 1;if (!f[p][q])f[p][q] = ++id; //如果不存在该节点,创造该节点p = f[p][q];ans1 += cnt[p]; //如果能够连接在一起,词链加1}cnt[p]++; //单词末尾记录ans = max(ans, ans1); //找到最长词链return ans;
}
int main()
{cin >> n;for (int i = 1; i <= n; i++) {cin >> s;sum = solve(s);}cout << sum+1 << endl; //加一是因为最开始的那个起始单词没有纳入return 0;
}