子串的个数(惨遭水题无情吊打!!!)

子串的个数

给你一个由小写字母“a,b,c,d,e”构成的字符串S,请找出S中包含了多少个不同的长度为N的子串。例如,给出的字符串是"daababac",N的值为3,那么长度为3的不同子串有"daa"; "aab"; "aba"; "bab"; "bac",最后输出的结果是5。

一开始给你一个空字符串S,有两个操作需要你完成:

编号“1”:在S后添加一个字符串S’,(也就是字符串加法S=S+S’);

编号“2”:输出当前S中包含的不相同的长度为N的字符串的个数;

输入格式:

第一行,一个整数N

第二行,一个整数M,表示下面有M个操作

接下来M行,每行表示一个操作(1号操作为数字1,然后是一个空格,接着是一个字符串,2号操作只有一个数字2)。

输出格式:

对于每个编号2的操作,输出一整数,表示所求结果。

样例输入1:

样例输入2:

3

4

1 daababac

2

1 acc

2

4

5

1 ebaedabedaedbaedaedbaedbaeadeaccccccc

1 ddddd

1 abcd

2

样例输出1:

样例输出2:

5

8

24

28

数据范围:

对于  50% 的数据:1≤M≤100    1≤字符串S最终的长度≤10,000    1≤N≤8

对于 100% 的数据:1≤M≤1000   1≤字符串S最终的长度≤200,000   1≤N≤8

—————————————————————————————————————————————————————————————————————————————

这道题有很多种解法,简记一下。

1.trie树;

=========================

这是一颗神奇的树!

注意从原点0 开始,漫漫坑跌路,被坑了几次了!

但毫无疑问,这是最快的。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
struct node{int s[5];};
node trie[200005];
char B[200005],A[200005];
int n,m,now,cnt,tot;

void insert(char a[10])
{
	int i,p=0;
	bool mark=0;
	for(i=1;i<=n;i++)
	{
		int t=a[i]-'a';
		if(trie[p].s[t])p=trie[p].s[t];
		else
		{
			tot++;mark=1;
			p=trie[p].s[t]=tot;
		}
	}
	if(mark)cnt++;
}
int main()
{
//	freopen("data7.in","r",stdin);
//	freopen("data.out","w",stdout);
	int i,j,k,t,p=1,q,l;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++)
	{
		scanf("%d",&k);
		if(k==1)
		{
			scanf("%s",A+1);
			A[0]=' ';
			l=strlen(A)-1;
			q=1;
			while(q<=l)
			{
				for(j=p;j<=n;j++)
				{
					B[j]=A[q++];
//				printf("-%c-",B[j]);
				}
//				for(j=1;j<=n;j++)printf("-%c-",B[j]);
//				putchar(10);
				B[0]=' ';
//				for(j=1;j<=n;j++)printf("%c",B[j]);
				if(j==n+1)
				{
					insert(B);
					for(j=1;j<n;j++)B[j]=B[j+1];
					p=n;
				}
			}
		}
		if(k==2)printf("%d\n",cnt);
	}
//	system("pause");
	return 0;
}



2.hash;

=========================

我的hash写的很渣。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
string a="",b,s;
bool mark[17000000];
unsigned int hash(string s)
{
	unsigned int hash=0,seed=131;
	unsigned int i=0,len=s.length();
	while(i<len)hash=hash*seed+s[i++];
	return (hash&0xFFFFFF);
}
int main()
{
	int n,m,j,len,k,t,tot=0,i;
	scanf("%d%d",&n,&m);
	len=n-1;
	for(i=1;i<=m;i++)
	{
		scanf("%d",&k);
		if(k==1)
		{
			cin>>b;
			a+=b;
			for(j=len-n+1,len=a.length();j+n<=len;j++)
			{
				s=a.substr(j,n);
				t=hash(s);
				if(!mark[t])
				{
					tot++;
					mark[t]=1;
				}
			}
		}
		else printf("%d\n",tot);
	}
//	system("pause");
	return 0;
}


3.神奇的map;

=========================

万万没想到,唉,to young to simple;

但事实告诉我们,手写的确实要快一些。

#include<cstdio>
#include<iostream>
#include<map>
#include<cstring>
using namespace std;
map<string,int>mp;
string a="",b;
int main()
{
	int n,m,i,j,len,k;
	scanf("%d%d",&n,&m);
	len=n-1;
	for(i=1;i<=m;i++)
	{
		scanf("%d",&k);
		if(k==1)
		{
			cin>>b;
			a+=b;
			for(j=len-n+1,len=a.length();j+n<=len;j++)
			mp[a.substr(j,n)]++;
		}
		else printf("%d\n",mp.size());
	}
	return 0;
}

4.更神奇的5进制;

这不给我说,打死都想不到。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
bool mark[500000];
int Mod[]={1,5,25,125,625,3125,15625,78125,390625};
string a="",b,s;
int n;
int change(string s)
{
	int tot=0;
	for(int i=0;i<n;i++)tot+=(s[i]-'a')*Mod[i];
	return tot;
}
int main()
{
	int k,m,i,j,len,t,tot=0;
	scanf("%d%d",&n,&m);
	len=n-1;
	for(i=1;i<=m;i++)
	{
		scanf("%d",&k);
		if(k==1)
		{
			cin>>b;
			a+=b;
			for(j=len-n+1,len=a.length();j+n<=len;j++)
			{
				s=a.substr(j,n);
				t=change(s);
				if(!mark[t])
				{
					tot++;
					mark[t]=1;
				}
			}
		}
		else printf("%d\n",tot);
	}
	return 0;
}
(完)


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值