1455:【例题1】Oulipo

典型例题:给出两个字符串s1,s2,求s1在s2中出现多少次

ps.求子串的hash公式

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1e6+10;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
//字符串hash模板题
char s1[maxn],s2[maxn];
ull h[maxn];
ull power[maxn];  //每一步要乘的
ull b=27,mod=1<<31;
//只有大写字母 
int main(){
	power[0]=1;
	for(int i=1;i<=1000000;i++) power[i]=power[i-1]*b;
	int t;
	scanf("%d",&t);
	while(t--){
		scanf("%s",s1+1);
		scanf("%s",s2+1);
		int n=strlen(s1+1);
		int m=strlen(s2+1);
		h[0]=0;
		ull ans=0,s=0;
		for(int i=1;i<=m;i++){  //算出s2的hash值  每一位 
			h[i]=(h[i-1]*b+(ull)(s2[i]-'A'+1))%mod;
		}
		for(int i=1;i<=n;i++) s=(s*b+(ull)(s1[i]-'A'+1))%mod;   //s1的hash值 
		for(int i=0;i<=m-n;i++){
			if(s==h[i+n]-h[i]*power[n]) ans++;
		} 
		printf("%d\n",ans);
	}
return 0;
}

1456:【例题2】图书管理

 这道题可以直接用map来做,map<ull,int> a;

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=30010;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull; 
int n;
int mod1=100005;
int k1=233317;
map<ull,int> a; //用map来做 
char op[10],ss[210];
int main(){
	scanf("%d",&n);
	//int num=0;
	while(n--){
		scanf("%s ",op);
		gets(ss);
		ull num=0;
		for(int i=0;i<strlen(ss);i++)  //求出hash值
		num=(num*k1+(int)ss[i]);
		if(op[0]=='f'){
			if(a[num]==1) printf("yes\n");
			else printf("no\n");
		} 
		else a[num]=1;
	}
return 0;
}

1457:Power Strings

给定若干个长度 ≤106 的字符串,询问每个字符串最多是由多少个相同的子字符串重复连接而成的。如:ababab 则最多有 3 个 ab 连接而成。

abcd   1
aaaa   4
ababab  3
.

询问每个字符串最多是由多少个相同的子字符串重复连接而成的  求最短重复子序列(这样才能保证最多嘛
这道题试问我们一个串有几个循环节。循环节就是指相等的(真)前缀和(真)后缀的个数。我们知道,
kmp过程中的next[i]是这个意义:0-i-1位中相等的真前后缀个数。那么next[len]就是指0-len-1位中相等的真前后缀个数。

所以第一种做法就是,求next数组

所以要的最短重复子序列就是len-next[len]

if(len%(len-next[len])==0) printf("%d\n",len/(len-next[len]));

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1e6+10;
const int INF=0x3fffffff;
typedef long long LL;
//询问每个字符串最多是由多少个相同的子字符串重复连接而成的  求最短重复子序列
//这道题试问我们一个串有几个循环节。循环节就是指相等的(真)前缀和(真)后缀的个数。我们知道,
//kmp过程中的next[i]是这个意义:0-i-1位中相等的真前后缀个数。那么next[len]就是指0-len-1位中相等的真前后缀个数。
char s[maxn];
int next[maxn],len;
void getnext(){
	int j=-1;
	int i=0;
	next[0]=-1;
	while(i<len){
		if(j==-1||s[i]==s[j]){
			i++;j++;
			next[i]=j;
		}
		else j=next[j];
	}
}
int main(){
	while(1){
		scanf("%s",s);
		if(s[0]=='.') break;
		memset(next,0,sizeof(next));
		len=strlen(s);
		getnext();
		if(len%(len-next[len])==0) printf("%d\n",len/(len-next[len]));
		else printf("1\n");
	}
return 0;
}

第二种做法:普通做法,hash,判断连续k个字母的hash值是不是都是一样的,求子串的hash值

bool check(ull u,int k),分别是对应的hash值,还有就是这个重复子串的长度

//普通做法
#include<stdio.h>
#include<string.h>
using namespace std;
const int maxn = 1e6+10;
typedef unsigned long long ull;
char s1[maxn];
ull power[maxn],h[maxn];
ull n,s,base=131,mod=1<<31;
int check(ull v,int k){
	for( ull i=0; i<n; i+=k ){
		if(h[i+k]-h[i]*power[k]!=v) return 0;  //计算字串的hash值 
	}
	return 1;
}
int main(){
	power[0]=1;
	for( int i=1; i<=101000; i++ ) power[i]=power[i-1]*base;
	while(scanf("%s",s1+1)){
		if(s1[1]=='.') break;
		n=strlen(s1+1);
		h[0]=0;
		for( int i=1; i<=n; i++ ) h[i]=h[i-1]*base+(ull)(s1[i]-'A'+1);
		for( int i=1; i<=n; i++ ){
			if(n%i==0){
				if(check(h[i],i)==1){
					printf("%d\n",n/i);break;
				}
			}
		}
	}
}

1458:Seek the Name, Seek the Fame

给定若干字符串(这些字符串总长 ≤4×105​​ ),在每个字符串中求出所有既是前缀又是后缀的子串长度

例如:ababcababababcabab,既是前缀又是后缀的:ab,abab,ababcabab,ababcababababcabab。

前后缀:肯定就想到了next数组

这道题不需要重复求出next数组,只需要不断向前移动next

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=4e5+10;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
//又是next数组? 
char s[maxn];
int next[maxn];
int len=0;
void getnext(){
	int i=0,j=-1;
	next[0]=-1;
	while(i<len){
		if(j==-1||s[i]==s[j]) {
			i++;j++;
			next[i]=j;
		}
		else j=next[j];
	}
}
int op[maxn];
int main(){
	while(~scanf("%s",s)){
		memset(next,0,sizeof(next));
		len=strlen(s);
		getnext();
		int num=0;
		memset(op,0,sizeof(op));
		
	
		//不用循环做next数组,直接取呀!!! 
		for(int i=len;next[i]!=-1;){
			op[++num]=i; //len也写进来了 
			i=next[i];
		}
		for(int i=num;i>=1;i--) printf("%d ",op[i]);
		printf("\n"); 
	}
	
return 0;
}

1459:friends

根据题目意思,我们可以先求出字符串的HASH值,再枚举插入字符的位置然后判断字符串去掉这个字符后,用HASH计算两串是否相等的办法,判断能否分成两个相同部分。
分为三种情况:插在左边、插在右边、插在中间
然后计算三种情况下的hash值,看去掉当前这个字符,两边的hash值是不是相等

重点是怎样求中间空一个位置的串的hash值

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef unsigned long long ll;
char s[2100000];
ll len,ans,sum,x,b=1e9+7,p[2100000],a[2100000];
int main()
{
    scanf("%lld%s",&len,s+1);
    if(len%2==0)
    {
        printf("NOT POSSIBLE\n");
        return 0;
    }
    p[0]=1;
    a[0]=ans=0;
    for(int i=1;i<=len+10;i++)
    p[i]=p[i-1]*b;
    for(int i=1;i<=len;i++)
    a[i]=a[i-1]*b+s[i];
    for(int i=1;i<=len;i++)
    {
        bool bk=false;
        if(i<(len+1)/2)
        {
            if(a[i-1]*p[(len+1)/2-i]+a[(len+1)/2]-a[i]*p[(len+1)/2-i]
            ==a[len]-a[(len+1)/2]*p[len/2])
            sum=a[len]-a[(len+1)/2]*p[len/2],x=i,bk=true;
        }
        else
        if(i>(len+1)/2)
        {
            if(a[len/2]
            ==(a[i-1]-a[len/2]*p[i-1-len/2])*p[len-i]+a[len]-a[i]*p[len-i])
            sum=a[len/2],x=i,bk=true;
        }
        else
        if(i==(len+1)/2)
        {
            if(a[len/2]==a[len]-a[(len+1)/2]*p[len-i])
            sum=a[len/2],x=i,bk=true;
        }
        if(ans&&bk)
        {
            if(ans!=sum)
            {
                printf("NOT UNIQUE\n");
                return 0;
            }
        }
        else
        ans=sum;
    }
    if(!ans)
    printf("NOT POSSIBLE\n");
    else
    {
        for(int i=1;i<=len/2;i++)
        {
            if(i<x)
            printf("%c",s[i]);
            else
            printf("%c",s[i+1]);
        }
        printf("\n");
    }
    return 0;
} 

1460:A Horrible Poem

这道题也是求最短循环节的,但是有两个点会超时(怎么过的

P3538 [POI2012]OKR-A Horrible Poem - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

1、循环节一定是长度的约数
2、如果n是一个循环节,那么k*n也必定是一个循环节(关键所在)
3、n是[l,r]这一段的循环节  的充要条件是  [l,r-n]和[l+n,r]相同(利用这个性质我们在判断是否为循环节是可以做到O(1))  
所以我们可以在求出这个区间的长度之后,判断它的每个约数是否是循环节(应用性质3),并且因为性质1,它的约数是循环节,原串一定也是。

所以只要不断除以质因数(相当于从大到小枚举约数),缩小L的长度,最后就是最小的长度。

而一个重要的点在于,用上面方法来枚举约数是为了避免tle

在求它的质因数的时候,可以通过线性筛的过程求得,将时间法度由根号n 降为logn。

注意这里枚举到全长。

这样通过nxt数组不断回跳,就可以找出所有质因数(多次乘方的也可以)

判定循环节的时候可以使用hash。

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define seed 13131
#define maxn 500005
using namespace std;
typedef unsigned long long ull;
char s[500005];
ull s1[500005];
ull ss[500005];
int sushu[500005];
int used[500005];
int nxt[500005];
int k;
int ys[500005];
void pri()
{
    for(int i = 2;i<= maxn;i++)
    {
        if(used[i] == 0)
        {
            sushu[++k] = i;
            nxt[i] = i;
        }
        for(int j = 1;j <= k && (long long)i*sushu[j]<= maxn;j++)
        {
            used[i*sushu[j]] = 1;
            nxt[i*sushu[j]] = sushu[j];
            if(i%sushu[j] == 0)
            {
                break;
            }
        }
    }
}
int check(int l1,int r1,int l2,int r2)
{
    if(s1[r1]-ss[r1-l1+1]*s1[l1-1] == s1[r2]-ss[r2-l2+1]*s1[l2-1])
    {
        return 1;
    }
    return 0;
}
int main()
{
    int n;
    scanf("%d", &n);
    scanf("%s",s+1);
    int q;
    scanf("%d", &q);
    for(int i = 1;i <= n;i++)
    {
        s1[i] = s1[i-1]*seed+s[i]-'a'+1;
    }
    ss[0] = 1;
    for(int i = 1;i <= n;i++)
    {
        ss[i] = ss[i-1]*seed; 
    }
    pri();
    for(int i = 1;i <= q;i++)
    {
        int l,r;
        scanf("%d%d", &l, &r);
        int len = r-l+1;
        int tt = 0;
        while(len != 1)
        {
            ys[++tt] = nxt[len];
            len = len/nxt[len];
        }
        len = r-l+1;
        for(int j = 1;j <= tt;j++)
        {
            int t = len/ys[j];
            if(check(l,r-t,l+t,r) == 1)
            {
                len = t;
            }
        }
        printf("%d\n",len);
    }
    return 0;
}

  

1461:Beads

 

 

 看怎样除这个,能获得多种类型的子串

有一点要注意,就是正反串的hash值,1 2 3 和3 2 1是一样的,所以要正反都求一次hash值,用map来判断,但是有一点,应该是用h1*h2的值作为map的键值
不然一个map存正向的,一个map存反向的,会超时

可以想到存储格式:map

正向的子串hash:suml[j]-suml[j-i]*p[i];

反向的子串hash:sumr[j-i+1]-sumr[j+1]*p[i]

#include <bits/stdc++.h>
typedef unsigned long long ll;
using namespace std;
int n,a[200005],ans[200005],total=1;
ll p[200005],suml[200005],sumr[200005],b=1000000007;
map<ll,int>mp;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int i,j,c=0,maxn=1;
    cin>>n;
    p[0]=1;
    for(i=1;i<=n;i++)
    {
        cin>>a[i];
        p[i]=p[i-1]*b,suml[i]=suml[i-1]*b+a[i];
    }
    for(i=n;i>=1;i--)
    {
       sumr[i]=sumr[i+1]*b+a[i];
    }
    for(i=1;i<=n;i++) /**< i用来表示字串长度,最大为n,不可以用n/2*/
    {
        mp.clear();
        c=0;
        for(j=i;j<=n;j+=i)
        {
            ll h1=suml[j]-suml[j-i]*p[i];
            ll h2=sumr[j-i+1]-sumr[j+1]*p[i];
            ll h3=h1*h2;  /**< 正反认为同一个串,所以如果两串相同,
            正向hash值h1和反向hash值h2的乘积的值必然一样 */
            if(!mp[h3])
            {
                c++;
                mp[h3]=1;
            }
        }
        if(c>maxn)
        {
            maxn=c;
            total=1;
            ans[total++]=i;
        }
        else if(c==maxn)
        {
            ans[total++]=i;
        }
    }
    cout<<maxn<<' '<<total-1<<endl;
    for(i=1;i<total;i++)
        cout<<ans[i]<<' ';
    return 0;
}

1462:Antisymmetry

 

0\1取反和对称操作的前后顺序显然不影响,先考虑对称操作再考虑取反,于是可以发现子串长度显然是偶数而且关于对称轴0/1对称(一边为0则另一边为1)。
算法1: 枚举对称轴,二分+hash。时间复杂度O(nlog(n))。

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define seed 13131
#define maxn 500010
#define LL long long
using namespace std;
typedef unsigned long long ull;
char s[maxn]; 
int a[maxn],b[maxn],n;
LL ha[maxn],hb[maxn],p[maxn]; //原串和原串的hash  取反后的串和hash
const int md=1e9+7;
LL geta(int l,int r){  //原串的子串值 
	return (ha[r]-ha[l-1]*p[r-l+1]%md+md)%md;
}
LL getb(int l,int r){
	return (hb[l]-hb[r+1]*p[r-l+1]%md+md)%md;
}
int query(int x){
	int l=1,r=n/2;
	while(l<=r){
		int mid=(l+r)>>1;
		if(mid>=1&&x+mid<=n&&geta(x-mid+1,x+mid)==getb(x-mid+1,x+mid)) l=mid+1;
		else r=mid-1;
	}
	return r;
}
int main(){
	scanf("%d",&n);
	scanf("%s",s+1);
	for(int i=1;i<=n;i++) a[i]=s[i]-'0';
	for(int i=1;i<=n;i++) b[i]=1-a[i];
	ha[0]=1;hb[n+1]=1;p[0]=1;
	for(int i=1;i<=n;i++) ha[i]=(ha[i-1]*seed%md+a[i])%md,p[i]=p[i-1]*seed%md;
	for(int i=n;i>=1;i--) hb[i]=(hb[i+1]*seed%md+b[i])%md;
	LL ans=0;
	for(int i=1;i<=n;i++){
		ans+=query(i);
	}
	printf("%lld\n",ans);
	return 0;
}

  


算法2: manacher算法,O(n)的时间算出所有子串最长回文子串长度(此题改下判断条件就好)。

!!!!怎么想到马拉车算法的?因为要旋转,先不考虑取反,如果连在一起是对称的话,就说明是反的,所以想到了马拉车算法https://blog.csdn.net/yanghongMO/article/details/52673305 

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn= 500010; 
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
//先全部反转,两个串都求hash,然后比较子串,哪些两个hash值相等
int n;

/*
0\1取反和对称操作的前后顺序显然不影响,先考虑对称操作再考虑取反,于是可以发现子串长度显然是偶数而且关于对称轴0/1对称(一边为0则另一边为1)。
算法1: 枚举对称轴,二分+hash。时间复杂度O(nlog(n))。
算法2: manacher算法,O(n)的时间算出所有子串最长回文子串长度(此题改下判断条件就好)。

*/
//理解马拉车算法呀
//https://blog.csdn.net/yanghongMO/article/details/52673305 
char c[maxn*2];  
char s[maxn]; 
int len[maxn*2];
int main(){
	scanf("%d %s",&n,s+1);
	c[0]='$';
	for(int i=1;i<=n;i++){
		c[i*2-1]='#';
		c[i*2]=s[i];
	}
	c[2*n+1]='#';
	c[2*n+2]='$';
	int mx=0,po=0;
	ull ans=0;
	for(int i=1;i<=2*n;i+=2){
		if(mx>i) len[i]=min(mx-i,len[2*po-i]);
		else len[i]=1;
		while((c[i+len[i]]==c[i-len[i]]&&c[i+len[i]]=='#')||(c[i-len[i]]-'0'+c[i+len[i]]-'0'==1)) len[i]++;  //反对称的要求就是从中间向两边扩展的每两个数相加都是1
		//由于我们需要的是长度为偶数的回文串,所以只需考虑 ‘#’ 的位置(就是Manacher添加的那些字符).  
		if(len[i]+i>mx){
			mx=len[i]+i;
			po=i;
		} 
		ans+=len[i]/2;
	}
	printf("%lld\n",ans);
return 0;
}

1463:门票

 有三种方法,第一种会超时

(1)第一种就是用一个散列表,如果存在,就输出,不存在就保存

注意这个存储方法很像链式前向星

#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int P=100003; int a,b,c,x=1,s,last[P];
struct node { int x,pre; }; vector<node>f;
//这里用vector是想优化一下空间,事实上数组即可
//有一个点通不过 
//https://blog.csdn.net/bcr_233/article/details/100167093
int find() {
	for (int i=last[s]; ~i; i=f[i].pre) 
		if (f[i].x==x) return 1;
	return 0;
}
int main() {
	scanf("%d%d%d",&a,&b,&c);
	memset(last,-1,sizeof last);
	f.push_back({1,-1}); last[1]=0;
	for (int i=1; i<=2000000; ++i) {
		x=(1ll*a*x+x%b)%c; s=x%P;
		if (find()) return printf("%d\n",i),0;
		f.push_back({x,last[s]}); last[s]=f.size()-1;
	}
	puts("-1"); return 0;
}

(2)双hash,过了

双哈希一般是不会被卡掉的,直接认为是正确的就好了
不过这种做法空间是线性的,仍然需要占用 2MB+ 的空间,事实上我们有更优的解法。

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=2e6;
const int INF=0x3fffffff;
typedef long long LL;
//双hash
//双哈希一般是不会被卡掉的,直接认为是正确的就好了
//不过这种做法空间是线性的,仍然需要占用 2MB+ 的空间,事实上我们有更优的解法。
const int P1  =249439;
const int P2 = 414977;
int a,b,c;
int vis1[P1],vis2[P2];
int p1,p2; 
int main(){
	scanf("%d %d %d",&a,&b,&c);
	p1=1;
	p2=1;
	vis1[1]=1;vis2[1]=1;
	for(int i=1;i<=maxn;i++){
		p1=(1ll*p1*a+p1%b)%c;
		p2=(1ll*p2*a+p2%b)%c;
		int m1=p1%P1;
		int m2=p2%P2;
		if(vis1[m1]&&vis1[m1]==vis2[m2]){
			printf("%d\n",i);
			return 0;
		}
		if(!vis1[m1]) vis1[m1]=i;
		if(!vis2[m2]) vis2[m2]=i;  //是同一个数产生的 
	}
	printf("-1\n");
	return 0;
} 

(3)数学方法

观察数列的递推式可以看出,这个数列是存在循环节的。
//首先找到循环节长度,然后开始找循环开始的地方
//也就是循环节的起点,

根据题目要求,循环节长度不能超过 2e6,所以 a2e6一定在这个循环里面。
于是我们找到第一个和 a2e6等的元素,它们之间的距离就是循环节的长度 len
如果没有找到则说明循环节长度大于2e6,此时输出-1
于是我们可以分别从 a0和 alen开始同时往后计算,找到的第一对相等元素即是答案。

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=2e6;
const int INF=0x3fffffff;
typedef long long LL;
 //数学做法 
//观察数列的递推式可以看出,这个数列是存在循环节的。 
//首先找到循环节长度,然后开始找循环开始的地方
//也就是循环节的起点,
/*
根据题目要求,循环节长度不能超过 2e6,所以 a22e6一定在这个循环里面。
于是我们找到第一个和 a2e6等的元素,它们之间的距离就是循环节的长度 len
如果没有找到则说明循环节长度大于2e6,此时输出-1
于是我们可以分别从 a0和 alen开始同时往后计算,找到的第一对相等元素即是答案。
*/ 
int a,b,c;
int s1=1,s2=1;
int len=0; //循环节长度
 
int main(){
	scanf("%d %d %d",&a,&b,&c);
	//首先计算a[inf]
	for(int i=1;i<=maxn;i++){
		s1=(1ll*s1*a+s1%b)%c;
	} 
	if(s1==1){ //首先判断a[0]是否与a[inf]相等
		len=INF;
	}
	for(int i=1;i<maxn;i++){ //注意这里不能取等号
   		s2=(1ll*s2*a+s2%b)%c;
   		if(s1==s2){
   			len=maxn-i;  //记录两元素的距离
		   }
	} //这样更新以后len就是最短循环节长度
	//循环结束后,len更新至最小值,即是循环节长度
	if(!len){
		printf("-1\n");return 0;   //没有更新len,说明循环节长度大于inf
	} 
	s1=s2=1;
	for(int i=1;i<=len;i++) s2=(1ll*s2*a+s2%b)%c;  //计算a[len]的时候的值 
	for(int i=0;i<=maxn;i++){
		if(s1==s2){
			printf("%d",len+i);
			return 0;
		}
		s1=(1ll*s1*a+s1%b)%c;  //分别从0、len开始算,直到算到相等的地方,这里就是循环开始的地方 
		s2=(1ll*s2*a+s2%b)%c;
		
	}
	printf("-1");
	return 0;
}

1464:收集雪花

 

 

 用map就可以了,有点像尺取法

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1e6+10;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
//可以直接用map
//我这个连题目都能读错的混账 
int n;
int a[maxn],l=1,r;
map<int,int> mp; //判断存不存在 
int main(){
	scanf("%d",&n);
	int len=0;
	for(r=1;r<=n;r++){
		scanf("%d",&a[r]);
		if(mp.find(a[r])!=mp.end()){ //存在 
			while(a[l]!=a[r]) mp.erase(mp.find(a[l++]));  //一直删掉直到相同,然后也把相同的删掉 
			l++;
		}
		else mp[a[r]]=1;
		len=max(len,r-l+1);  //记录最长的种类数 
	}
	printf("%d",len);
return 0;
}

  

 

 posted on 2020-04-17 11:27  shirlybabyyy  阅读(1163)  评论(0编辑  收藏  举报