题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4821
题目大意:给你M,L两个字母,问你给定字串里不含M个长度为L的两两相同的子串有多少个?
哈希+枚举
我就是不会枚举这样的,这次涨姿势了。
每次枚举起点,然后就能枚举全部的。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <map> 7 #include <set> 8 using namespace std; 9 typedef unsigned long long ull; 10 11 const ull B = 100*1000*1000+7; 12 int M,L; 13 char s[100010]; 14 ull h[100010]; 15 ull base[100010]; 16 ull tt[100010]; 17 18 int main(){ 19 base[0] = 1; 20 for(int i=1;i<100010;i++) base[i] = base[i-1]*B; 21 while(scanf("%d%d",&M,&L)!=EOF){ 22 memset(h,0,sizeof(h)); 23 scanf("%s",s); 24 int len = strlen(s); 25 for(int i=0;i<len;i++){ 26 if( i==0 ) h[i] = s[i]; 27 else h[i] = h[i-1]*B + s[i]; 28 } 29 int ans = 0; 30 // printf("len = %d\n",len); 31 for(int i=0;i<L;i++){ // 枚举全部起点 32 // puts("*******************"); 33 int cnt = 0; 34 map<ull,int> H; 35 for(int j=i;j+L<=len;j+=L){ // 枚举每段 36 tt[cnt++] = h[j+L-1] - (j==0?0:(h[j-1]*base[L])); 37 // printf("%d => %llu\n",j,tt[cnt-1]); 38 } 39 // printf("cnt=%d\n",cnt); 40 // 迟取法取每段然后数数,注意这里的j<min(cnt,M) 41 for(int j=0;j<min(cnt,M);j++){ 42 // printf("******%llu\n",H[tt[j]]); 43 H[tt[j]]++; 44 } 45 if( H.size()==M ){ 46 ans++; 47 // printf("%d==%d\n",H.size(),M); 48 } 49 for(int j=M;j<cnt;j++){ 50 H[tt[j-M]]--; 51 if( H[tt[j-M]]==0 ) H.erase(tt[j-M]); 52 H[tt[j]]++; 53 if( H.size()==M ){ 54 ans++; 55 // printf("%d==%d\n",H.size(),M); 56 } 57 } 58 } 59 printf("%d\n",ans); 60 } 61 return 0; 62 }
时间: 2024-08-24 06:06:36