day2:字符串问题总结
一看题,就知道用KMP算法,但是开始用字符串存,发现WA了,于是想到由于数字太大,然后在ASCII码值中没有对应的值,于是就直接采用用整形数组存,然后用KMP算法
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int s1[1000010];
int s2[10010];
int Next[10010];
int main()
{
int t;
int n,m;
int num;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
scanf("%d",&s1[i]);
}
s1[n]='\0';
for(int i=0;i<m;i++)
{
scanf("%d",&s2[i]);
}
s2[m]='\0';
memset(Next,0,sizeof(Next));
Next[0]=-1;
int i=0;
int j=-1;
while(i<m)
{
if(j==-1||s2[i]==s2[j])
{
++i;
++j;
Next[i]=j;
}
else
{
j=Next[j];
}
}
i=0,j=0;
while(i<n&&j<m)
{
if(j==-1||s1[i]==s2[j])
{
++i;
++j;
}
else
j=Next[j];
}
if(j==m)
{
printf("%d\n",i-m+1);
}
else
printf("-1\n");
}
return 0;
}
一看也就是用KMP,求子串在模式串中的位置,稍微对KMP算法模板变下行即可;
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
char s1[1010];
char s2[1010];
int Next[1010];
int main()
{
while(~scanf("%s",s1))
{
if(strcmp(s1,"#")==0)
break;
scanf("%s",s2);
int len1=strlen(s1);
int len2=strlen(s2);
s1[len1]='\0';
s2[len2]='\0';
memset(Next,0,sizeof(Next));
int i=0;
int j=-1;
Next[0]=-1;
while(i<len2)
{
if(j==-1||s2[i]==s2[j])
{
++i;
++j;
Next[i]=j;
}
else
j=Next[j];
}
int num=0;
i=0,j=0;
while(i<len1&&j<len2)
{
if(s1[i]==s2[j]||j==-1)
{
++i;
++j;
}
else
j=Next[j];
if(j==len2)
{
j=0;
num++;
}
}
printf("%d\n",num);
}
return 0;
}
看题目发现,如果直接还是单纯用KMP的话,肯定会TLE,这一看就是标准的多模式匹配问题
固然想到AC自动机算法,于是直接套模板即可;
/**单纯用KMP肯定会TLE,于是就想到用AC自动机,发现直接就是套模板即可*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
char str[1000010];
char s[55];
int Tire[1000010][30]; //存字典树
int wordNum[1000010]; //以某结点结束的字符串个数
int fail[1000010]; //失败指针
int cnt=0;
/**建立字典树*/
void build_Tire(char s[])
{
int root=0;
int len=strlen(s);
for(int i=0;i<len;i++)
{
int c=s[i]-'a';
if(!Tire[root][c])
Tire[root][c]=++cnt;
root=Tire[root][c];
}
wordNum[root]++; //该位置结束的字符串共有多少个
}
void get_Fail()
{
queue<int>q;
/**第二层给失败指针赋值*/
for(int i=0;i<26;i++)
{
if(Tire[0][i])
{
fail[Tire[0][i]]=0;
q.push(Tire[0][i]);
}
}
/**遍历字典树以获得所有失败指针*/
while(!q.empty())
{
int v=q.front(); //当前节点
q.pop();
for(int i=0;i<26;i++)
{
if(Tire[v][i])
{
fail[Tire[v][i]]=Tire[fail[v]][i];
q.push(Tire[v][i]);
}
else
Tire[v][i]=Tire[fail[v]][i];
}
}
}
/**查询*/
int query()
{
int now=0,ans=0;
int len=strlen(str);
for(int i=0;i<len;i++)
{
int c=str[i]-'a';
now=Tire[now][c];
for(int j=now;j&&wordNum[j]!=-1;j=fail[j])
{
ans+=wordNum[j];
wordNum[j]=-1;
}
}
return ans;
}
int main()
{
int n,m;
scanf("%d",&n);
while(n--)
{
memset(Tire,0,sizeof(Tire));
memset(wordNum,0,sizeof(wordNum));
scanf("%d",&m);
for(int i=0;i<m;i++)
{
scanf("%s",s);
build_Tire(s);
}
get_Fail();
scanf("%s",str);
int ans=query();
printf("%d\n",ans);
}
return 0;
}
D题:hdu 2778:LCR
一道模拟题,但是没做出来,待补。。。。
这题就很无语,难度不是太难,就是求多个模式串的前缀是否等于待匹配串,求出个数,直接就是套字典树模板即可,但是它那个数大小就真的很懵,开小点就Runtime Error,大一点就MLE,然后在杭电交就莫名其妙的过了
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn =2e6+5;
int n,m;
int flag;
int str[maxn][30];
int sum[maxn];
char ss[maxn];
void Insert(char *ss)
{
int p = 0;
for(int i = 0; i < strlen(ss); i++)
{
int c = ss[i] - 'a';
if(!str[p][c]) str[p][c] = ++flag;
sum[str[p][c]]++;
p = str[p][c];
}
}
int query(char *k)
{
int p = 0;
for(int i = 0; i < strlen(k); i++)
{
int c = k[i] - 'a';
if(!str[p][c]) return 0;
p = str[p][c];
}
return sum[p];
}
int main()
{
flag = 0;
while(gets(ss))
{
if(ss[0] == '\0') break;
Insert(ss);
}
char k[maxn];
//printf("111");
while(~scanf("%s",k))
{
printf("%d\n",query(k));
}
return 0;
}
F题:hdu 2072:单词数
同样也是一道字典树的题,但是用set会更加简单,而今天又是学字符串,但是我还是用set写的,hhh
/**i dislike submit failed*/
#include<bits/stdc++.h>
using namespace std;
int main()
{
string str,word;
set<string>SET;
int n;
while(getline(cin,str))
{
SET.clear();
n=0;
if(str!="#")
{
stringstream ss(str);
while(ss>>word)
{
n++;
SET.insert(word);
}
cout<<SET.size()<<endl;
}
else
break;
}
return 0;
}
G题:hdu 2243
待补。。。
同样也是一道字典树模板题,敲完即可
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100010;
int Tire[maxn][26];
int wordNum[maxn];
char str[100010][20];
int cnt=0;
void build_Tire(char str[])
{
int len=strlen(str);
int root=0;
for(int i=0;i<len;i++)
{
int c=str[i]-'0';
if(!Tire[root][c])
Tire[root][c]=++cnt;
root=Tire[root][c];
/**重点在这里*/
wordNum[root]++;
}
}
int Find(char str[])
{
int root=0;
int len=strlen(str);
for(int i=0;i<len;i++)
{
int c=str[i]-'0';
if(Tire[root][c]==0)
return 0;
root=Tire[root][c];
}
return wordNum[root];
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
memset(Tire,0,sizeof(Tire));
memset(wordNum,0,sizeof(wordNum));
cnt=0;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s",str[i]);
build_Tire(str[i]);
}
int flag=0;
for(int i=0;i<n;i++)
{
if(Find(str[i])>1)
{
flag=1;
break;
}
}
if(flag==0)
printf("YES\n");
else
printf("NO\n");
}
}
今天还是偷懒了,后缀数组都没看下,然后另外一套居然一道题都没做。。。
加油加油,明天选拔赛但愿能多做出来几道