Distinct Count
时间限制:3000 ms | 内存限制:65535 KB
难度:3
- 描述
- 给一个长度为
n 的数列 {an} ,找出有多少个长度为 m 的区间,使区间中不含有重复的数字。
- 输入
- 多组测试数据。(200组)
第 1 行有 2 个数,n,m。(1<=n,m<=10^5)
接下来 1 行有 n
个数,ai。(|ai|<=10^9) - 输出
- 1 行有 1 个数,满足条件的区间的个数。
- 样例输入
6 3
1 6 2 6 3 6- 样例输出
2
讲解:昨天下午和晚上,我和zz都在想这道题,昨天夜里睡觉之前想了下,还是没思路,今天早晨读书时突发灵感啊,算是想清楚了,嘎嘎,特来纪念一下;
我们可以采用左减,右加的方式来解决;依次向右滑动;
线把前m个出现的数标记成1,当然会有重复的,于是用 map 进行计重;map的指向为与之相同前一个数的下标;
也就是说把n个中出现多次的数,只把,最后一个数,标记为1,前面的都为0;然后求和时,这个数,就算了一次;
案例:sum 每 n个数的和;
7 3
1 6 2 6 3 6 7
1 1 1 sum=3;
1 0 1 1 sum=sum-b[1] =2
1 0 1 1 1 sum=sum+1-b[2]=3
1 0 1 0 1 1 sum=sum-b[3] =2 //当前的已经出现过了,不在加了,只减去前面的
1 0 1 0 1 1 1 sum=sum+1-b[4]=3
AC代码:1 #include<iostream>
2 #include<cstdio>
3 #include<algorithm>
4 #include<cstring>
5 #include<string>
6 #include<cmath>
7 #include<map>
8 #include<queue>
9 using namespace std;
10 const int N=1e5+5;
11 int a[N],b[N];
12 int main()
13 {
14 int ans,sum,m,n;
15 map<long long ,int >ma;
16 while(cin>>m>>n)
17 {
18 ma.clear();
19 memset(b,0,sizeof(b));
20 sum=0;ans=0;
21 for(int i=1 ; i<=m ;i++)
22 {
23 scanf("%d",&a[i]);
24 if(i<=n)
25 {
26 if(ma[ a[i] ]==0)
27 {
28 sum=sum+1; //统计前n个共有几个数;
29 ma[ a[i] ]=i; //标记一下,下标;
30 b[i]=1; //如果此数没有出现,标记为1;
31 }
32 else {
33 b[ ma[i] ]=0; //如果已经出现了,把前面的标记为0;
34 b[i]=1; //当前的为1;
35 ma[ a[i] ]=i; //并更新下标,方便下一次更新;
36 }
37 }
38 }
39
40 if(n==1)
41 { printf("%d\n",m);continue;}
42 if(sum==n)
43 ans++;
44 for(int i=n+1,j=1; i<=m ; i++,j++)
45 {
46 if(ma[a[i]]==0)//前面没有出现过,直接更新sum,b,ma
47 {
48 sum=sum+1;
49 ma[ a[i] ]=i;
50 b[i]=1;
51 }
52 else { //出现过了的,前面相同的更新为0,同时更新为新的下标,当前位置标记为1;
53 b[ma[a[i]]]=0;
54 ma[a[i]]=i;
55 b[i]=1;
56 }
57 sum=sum-b[j]; //减去最前面的数,就是这n个数的和;然后判断 sum是否等于n;
58 if(sum==n)
59 ans++;
60 }
61 cout<<ans<<endl;
62 }
63 return 0;
64 }
nyoj
时间: 2024-11-01 19:05:25