2018百度之星-资格赛-1002 子串查询 (前缀和)

题目链接 http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=820&pid=1002

题目描述

度度熊的字符串课堂开始了!要以像度度熊一样的天才为目标,努力奋斗哦!
为了检验你是否具备不听课的资质,度度熊准备了一个只包含大写英文字母的字符串 A[1,n] = a 1 a 2 ⋅ ⋅ ⋅ a n a_1a_2···a_n a1a2an,接下来他会向你提出 q 个问题 (l,r),你需要回答字符串 A[l,r]= a l a l + 1 ⋅ ⋅ ⋅ a r a_la_{l+1}···a_r alal+1ar内有多少个非空子串是 A[l,r] 的所有非空子串中字典序最小的。这里的非空子串是字符串中由至少一个位置连续的字符组成的子序列,两个子串是不同的当且仅当这两个子串内容不完全相同或者出现在不同的位置。
记 |S| 为字符串 S 的长度,对于两个字符串 S 和 T,定义 S 的字典序比 T 小, 当且仅当存在非负整数k ( ≤ min(|S|,|T|)) 使得 S 的前 k 个字符与 T 的前 k 个字符对应相同,并且要么满足 |S| = k且 |T| > k,要么满足k < min(|S|, |T|) 且 S 的第 k+1 个字符比 T 的第 k+1 个字符小。例如 “AA” 的字典序比 “AAA” 小,“AB” 的字典序比 “BA” 小。

输入描述

第一行包含一个整数 T,表示有 T 组测试数据。
接下来依次描述 T 组测试数据。对于每组测试数据:
第一行包含两个整数 n 和 q,表示字符串的长度以及询问的次数。
第二行包含一个长为 n 的只包含大写英文字母的字符串 A[1,n]。
接下来 q 行,每行包含两个整数 l i , r i l_i,r_i li,ri, 表示第i次询问的参数。
保证1 ≤ T ≤ 10,1 ≤ n,q ≤ 1 0 5 10^5 105, l ≤ l i ≤ r i ≤ n l ≤ l_i ≤ r_i ≤n llirin

输出描述

对于每组测试数据,先输出一行信息 “Case #x:”(不含引号),其中 x 表示这是第 x 组测试数据,接下来 q 行,每行包含一个整数,表示字符串 A[l,r] 中字典序最小的子串个数,行末不要有多余空格。

样例输入

1
2 3
AB
1 1
1 2
2 2

样例输出

Case #1:
1
1
1

题意
找出字符串某个区间字典序最小的子串的个数.

思路
首字母相同时,单个字母的字典序肯定比多个字母的字典序小,所以题目转化为找每段区间内ASCII码最小字母出现的次数, 利用前缀和的方法, 在输入时用二维数组sum[maxn][26]记录从第1个字母到i个字母所有字母出现的个数, 查询时sum[r][] - sum[l-1][]中第一个不为0的值就是答案.

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = 0x3f3f3f3f;
const int maxn = 100005;
int T,n,q,l,r,ans;
int s[maxn];
int sum[maxn][26];
char c;

int main() {
    scanf("%d", &T);
    for (int kase = 1; kase <= T; kase++) {
        memset(s, 0, sizeof(s));
        memset(sum, 0, sizeof(sum));
        scanf("%d %d", &n, &q);
        getchar();
        for (int i = 1; i <= n; i++) {
            scanf("%c", &c);
            s[i] = c - 'A';
            for (int j = 0; j < 26; j++) {
                sum[i][j] = sum[i - 1][j];
            }
            sum[i][s[i]]++;
        }
        printf("Case #%d:\n", kase);
        while (q--) {
        	ans = 0; 
            scanf("%d %d", &l, &r);
            for (int i = 0; i < 26; i++) {
                ans = sum[r][i] - sum[l - 1][i];
                if (ans) {
                    printf("%d\n", ans);
                    break;
                }
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Eimhin_Tang/article/details/81414075