百度之星2018资格赛1002题解
作为退役的老人家来光顾光顾百度之星。
据说资格赛水过一道题就行。。。就写那个签到题吧。orz
题目糊上,,,
度度熊的字符串课堂开始了!要以像度度熊一样的天才为目标,努力奋斗哦!
为了检验你是否具备不听课的资质,度度熊准备了一个只包含大写英文字母的字符串 A[1,n]=a1a2⋯anA[1,n]=a1a2⋯an,接下来他会向你提出 qq 个问题 (l,r)(l,r),你需要回答字符串 A[l,r]=alal+1⋯arA[l,r]=alal+1⋯ar 内有多少个非空子串是 A[l,r]A[l,r] 的所有非空子串中字典序最小的。这里的非空子串是字符串中由至少一个位置连续的字符组成的子序列,两个子串是不同的当且仅当这两个子串内容不完全相同或者出现在不同的位置。
记 ∣S∣∣S∣ 为字符串 SS 的长度,对于两个字符串 SS 和 TT ,定义 SS 的字典序比 TT 小,当且仅当存在非负整数 k(≤min(∣S∣,∣T∣))k(≤min(∣S∣,∣T∣)) 使得 SS 的前 kk 个字符与 TT 的前 kk 个字符对应相同,并且要么满足 ∣S∣=k∣S∣=k 且 ∣T∣>k∣T∣>k,要么满足 k<min(∣S∣,∣T∣)k<min(∣S∣,∣T∣) 且 SS 的第 k+1k+1 个字符比 TT 的第 k+1k+1 个字符小。例如 "AA" 的字典序比 "AAA" 小,"AB" 的字典序比 "BA" 小。
一开始看这个题,MD这么复杂,一看就是dalao出的题。
抓住关键词,字典序最小,首先考虑字符串长度最小,emmmm,当然是一个字母长度最小。
所以这个题就变成了,在一段字符区间中统计最小的那个字母出现了几次。
emmmmm,能把这么水的一个题说的这么高大上,我也是给出题人跪了。。。orz
用个前缀和思想。统计一下到当前位置每个字母出现几次,数组下标1~26表示A~Z出现的次数。
查询的时候从1到26循环若a[r]-a[l-1]不为零,就是他了,输出,跳出循环(这样字典序最小,因为相当于从A向Z找)。
说了这么多我相信都是废话,诸位大佬肯定能A掉这个题。emmmmmm
上代码。(丑得一逼)
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <vector> 5 #include <queue> 6 #include <deque> 7 #include <stack> 8 #include <string> 9 #include <cstdlib> 10 #include <cstring> 11 #define LL long long 12 using namespace std; 13 void read(int &x){ 14 char ch;x = 0;ch = getchar(); 15 while(ch < '0' || ch > '9') ch = getchar(); 16 while(ch >= '0' && ch <= '9'){ 17 x = x*10+ch-'0'; 18 ch = getchar(); 19 } 20 } 21 struct H { 22 int qq[26]; 23 }cc[100000+5]; 24 int T = 0,n,q,l,r,minn,num,cntt; 25 int cnt['Z'+5]; 26 char ch[100000+5]; 27 int main(){ 28 read(T); 29 while(T--){ 30 printf("Case #");++cntt; 31 printf("%d:\n",cntt); 32 read(n);read(q); 33 for(int i = 1;i <= n;i++) 34 scanf("%c",&ch[i]); 35 for(int i = 1;i <= n;i++){ 36 cc[i] = cc[i-1]; 37 cc[i].qq[ch[i]-'A']++; 38 } 39 for(int i = 1;i <= q;i++){ 40 read(l);read(r); 41 if(l == r){ 42 printf("1\n"); 43 continue; 44 } 45 else { 46 for(int j = 0;j < 26;j++){ 47 if(cc[r].qq[j]-cc[l-1].qq[j]!=0){ 48 printf("%d\n",cc[r].qq[j]-cc[l-1].qq[j]); 49 break; 50 } 51 } 52 } 53 } 54 } 55 return 0; 56 }