1.早上三个半小时
把昨天剩的那个题改正。
P1102错误原因:因为数据范围较大,所以A-B对数大于int型的数据范围,所以要用long long型来给A-B对数计数,最后的结果也不要忘记A-B的对数是long long型。
然后看了P2580这个题,这个题是字典树Tire的应用,因此看了讲解字典树的视频。
2.下午三个半小时
听学长讲课,然后完成了一个题目。
插入一下创建字典树的知识。
我们需要用到字典树来对字符串进场分析的时候就要将这个字符串放进我们的字典树(就像字典收录新词一样)但是没真正像收录新词那么难。我们只需要2步。
1.定义指向根节点的指针P,和一个交换用的指针Q。
2.从字符串开始下标到结束(0-len)我们依次将字符做出节点。方法是:将字母由字典序化为数字,则指针next[该字典序]指向的地方为空时我们开辟一个指针空间给Q,将其计数初始化为1。然后从0-MAXN将他next[]指向的全部初始化为NULL。再将P的next[字典序]指针指向Q,P更新为P的next[字典序]。若指针next[字典序]指向的地方已经有节点了,我们将其节点的计数++;更新P为P的NEXT。
P2580 于是他错误的点名开始了
P2580 于是他错误的点名开始了 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路
按照字典树的模板,根据输入的字符串,创建字典树,然后查询,点名过的就标记,然后再次点到的就输出REPEAT,没有再次点到就输出OK,否则输出WRONG。
原本我的思路是用哈希算法,求得每个字符串的哈希值,然后通过哈希值和是否访问过,得到每个字符串的结果,但是这种方法在标记字符串这个地方有点麻烦,所以就放弃了。
代码实现
#include<bits/stdc++.h>
using namespace std;
int trie[100001][26];
int cnt[100001];
int idx=0;
char s[55];
int n,m;
void Insert(string s)
{
int p=0;
for(int i=0;i<s.size();i++)
{
int c=s[i]-'a';
if(!trie[p][c])
trie[p][c]=++idx;//如果没有出现过就直接赋值
p=trie[p][c];//儿子结点的值
}
cnt[p]=1;//标记一下,表示已经出现
}
int query(string s)
{
int p=0;
for(int i=0;i<s.size();i++)
{
int c=s[i]-'a';
if(!trie[p][c])//没出现过
return 0;
p=trie[p][c];//儿子结点的值
}
if(cnt[p]==2)//重复出现
return 2;
if(cnt[p]==0)//没有出现过
return 0;
cnt[p]=2;
return 1;//出现一次
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",s);
Insert(s);
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%s",s);
int x=query(s);
if(x==1)
printf("OK\n");
else if(x>1)
printf("REPEAT\n");
else
printf("WRONG\n");
}
return 0;
}
3.晚上两个小时
重新学习了KMP字符串匹配,做了P3375 KMP字符串匹配模板题,但是还有错误,先挖个坑放这里,争取今晚就补上。
P3375 【模板】KMP字符串匹配
P3375 【模板】KMP字符串匹配 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路
先通过子串得到前缀数组,然后依次往后在主串中找与子串匹配的某段,然后得到匹配的片段的位置,直到主串的末尾。
代码实现
#include<stdio.h>
#include<string.h>
int prefix[1000001],prefix2[1000001];
char s1[1000001];
char s2[1000001];
int len1,len2;
void prefix_table(char s2[])
{
len2=strlen(s2);
prefix[0]=0;//前缀只有一个字母的时候,首尾相同的字母为0
int i=1,j=0;
while(i<len2)
{
if(s2[i]==s2[j])//已经匹配字母的后面一个字母与i移动到的字母匹配
{
j++;//最长能够匹配的长度加一
prefix[i]=j;
i++;
}
else
{
if(j>0)
j=prefix[j-1];
else
{
prefix[i]=j;
i++;
}
}
}
}
void KMP(char s1[],char s2[])
{
len1=strlen(s1);
len2=strlen(s2);
prefix2[0]=-1;
for(int i=1;i<len2;i++)
prefix2[i]=prefix[i-1];//习惯把前缀数组整体往后移动一个单位,第一个设为-1,方便KMP
int i=0,j=0;
while(i<len1)
{
if(j==len2-1&&s1[i]==s2[j])
{
printf("%d\n",i-j+1);
j=prefix2[j];
if(j==-1)
j++;
}
if(s1[i]==s2[j])
{
i++;
j++;
}
else
{
j=prefix2[j];
if(j==-1)
{
i++;
j++;
}
}
}
}
int main()
{
scanf("%s%s",s1,s2);
prefix_table(s2);
KMP(s1,s2);
len2=strlen(s2);
for(int i=0; i<len2; i++)
printf("%d ",prefix[i]);
return 0;
}
错误原因:KMP函数里if语句判断条件摆放位置有误,因为两个if判断语句里面都有两条语句在一个点能够匹配这个条件,所以除了有这个条件还有另一个条件的if语句要放前面。