2018百度之星资格赛T2 子串查询

【题解】

  很容易想到暴力做法:对于每个询问暴力查找区间内的最小字母,统计其出现次数。效率O(N^2),无法通过全部数据。

  我们可以换一个思路,设f[i][j]为第i个字母(字母‘A'到’Z'分别对应0到25)到第j个位置的出现次数和。

  对于每个询问[L,R],我们只要从0到25枚举每个字母,如果满足c[i][R]-c[i][L-1]>0,那么这个区间的这个字母出现过,输出其次数并break即可。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define LL long long
 5 #define rg register
 6 #define N 200010
 7 using namespace std;
 8 int T,t,n,m,l,r,ans,cnt[26][N];
 9 char c[N],mn;
10 inline int read(){
11     int k=0,f=1; char c=getchar();
12     while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
13     while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar();
14     return k*f;
15 }
16 inline void Pre(){
17     memset(cnt,0,sizeof(cnt));
18 }
19 int main(){
20     T=t=read();
21     while(T--){
22         printf("Case #%d:\n",t-T);
23         Pre();
24         n=read(); m=read();
25         for(rg int i=1;i<=n;i++){
26             c[i]=getchar();
27             while(c[i]<'A'||c[i]>'Z') c[i]=getchar();
28             cnt[c[i]-'A'][i]++;
29         }
30         for(rg int i=0;i<26;i++)
31             for(rg int j=1;j<=n;j++) cnt[i][j]+=cnt[i][j-1];
32         while(m--){
33             l=read(),r=read();
34             for(rg int i=0;i<26;i++) if(cnt[i][r]-cnt[i][l-1]>0){
35                 printf("%d\n",cnt[i][r]-cnt[i][l-1]);
36                 break;
37             }
38         }
39     }
40     return 0;
41 }
42 Close
View Code

猜你喜欢

转载自www.cnblogs.com/DriverLao/p/9425979.html