【2018百度之星资格赛】1002 子串查询

题目

  度度熊的字符串课堂开始了!要以像度度熊一样的天才为目标,努力奋斗哦!

为了检验你是否具备不听课的资质,度度熊准备了一个只包含大写英文字母的字符串 A[1,n]=a1a2⋯anA[1,n] = a_1 a_2 cdots a_nA[1,n]=a1​​a2​​an​​,接下来他会向你提出 qqq 个问题 (l,r)(l,r)(l,r),你需要回答字符串 A[l,r]=alal+1⋯arA[l,r] = a_l a_{l+1} cdots a_rA[l,r]=al​​al+1​​ar​​ 内有多少个非空子串是 A[l,r]A[l,r]A[l,r] 的所有非空子串中字典序最小的。这里的非空子串是字符串中由至少一个位置连续的字符组成的子序列,两个子串是不同的当且仅当这两个子串内容不完全相同或者出现在不同的位置。

∣S∣|S|S∣ 为字符串 SSS 的长度,对于两个字符串 SSS 和 TTT ,定义 SSS 的字典序比 TTT 小,当且仅当存在非负整数 k(≤min(∣S∣,∣T∣))k(leq min(|S|,|T|))k(min(S,T)) 使得 SSS 的前 kkk 个字符与 TTT 的前 kkk 个字符对应相同,并且要么满足 ∣S∣=k|S| = kS=k 且 ∣T∣>k|T| > kT>k,要么满足 k<min(∣S∣,∣T∣)k < min(|S|,|T|)k<min(S,T) 且 SSS 的第 k+1k+1k+1 个字符比 TTT 的第 k+1k+1k+1 个字符小。例如 "AA" 的字典序比 "AAA" 小,"AB" 的字典序比 "BA" 小。

分析

  对于每个查询题目说是求最小字串的数量,其实就是求这个区间内最小的字母出现的数目。然后就随便搞一下就可以了。

  我是直接建了个线段树,可以查询区间最小值,因为只包含大写字母,所以我也记录一下每个区间每个字母出现的次数。对于每个查询,先找出这个区间最小的字母是哪个,然后查询它出现的次数就可以了。

  rmq啥的应该也可以搞这个题。

  ac代码

  

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 
 6 using namespace std;
 7 const int maxn=100000+100;
 8 const int INF=2147400000;
 9 int T,n,q;
10 char s[maxn];
11 int minv[4*maxn],sumv[4*maxn][27];
12 void maintain(int o,int L,int R){
13     minv[o]=min(minv[2*o],minv[2*o+1]);
14     for(int i=0;i<26;i++)
15         sumv[o][i]=sumv[2*o][i]+sumv[2*o+1][i];
16 }
17 void build(int o,int L,int R){
18     if(L==R){
19         minv[o]=s[L]-'A';
20         sumv[o][s[L]-'A']=1;
21         return;
22     }
23     int M=L+(R-L)/2;
24     build(2*o,L,M);
25     build(2*o+1,M+1,R);
26     maintain(o,L,R);
27 }
28 int ql,qr;
29 int q_min(int o,int L,int R){
30     if(ql<=L&&qr>=R)
31         return minv[o];
32     int M=L+(R-L)/2;
33     int ml=INF,mr=INF;
34     if(ql<=M)
35         ml=q_min(2*o,L,M);
36     if(qr>M)
37         mr=q_min(2*o+1,M+1,R);
38     return min(ml,mr);
39 }
40 int v;
41 int q_sum(int o,int L,int R){
42     if(ql<=L&&qr>=R){
43         return sumv[o][v];
44     }
45     int res=0;
46     int M=L+(R-L)/2;
47     if(ql<=M)
48         res+=q_sum(2*o,L,M);
49     if(qr>M)
50         res+=q_sum(2*o+1,M+1,R);
51     return res;
52 }
53 int main(){
54     scanf("%d",&T);
55     for(int t=1;t<=T;t++){
56         printf("Case #%d:
",t);
57         scanf("%d%d",&n,&q);
58         scanf("%s",s+1);
59         memset(sumv,0,sizeof(sumv));
60         build(1,1,n);
61         for(int i=1;i<=q;i++){
62             scanf("%d%d",&ql,&qr);
63             v=q_min(1,1,n);
64             printf("%d
",q_sum(1,1,n));
65         }
66     }
67 return 0;
68 }
69 //CODE FROM LQLlulu
View Code

  

原文地址:https://www.cnblogs.com/LQLlulu/p/9418674.html