前缀和(减少时间复杂度)

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

为了检验你是否具备不听课的资质,度度熊准备了一个只包含大写英文字母的字符串 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

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;

const int maxn = 1e5 + 10;
char s[maxn];
int num[maxn][30];
int main(){
    int t;
    int cases = 0;
    scanf("%d",&t);
    int k = 0;
    while(t--){
        //memset(num,0,sizeof(num));
        int n,q;
        scanf("%d %d",&n,&q);
        getchar(); 
        printf("Case #%d:\n",++cases);
//      for(int i=1;i<=n;i++)
//          scanf("%c",&a[i]);

        scanf("%s",s+1);
        for(int i=1;i<=n;i++){
            for(int j=0;j<26;j++){  
                //int ch = a[i] - 'A';
                if(j == s[i] - 'A')
                    num[i][j] = num[i-1][j]+1;//ch用来标记字符,i用来标记区间
                else 
                    num[i][j] = num[i-1][j];
            } 
        }//仍为dp 
        int l,r;    
        //printf("%d\n",num[1][1]);
        while(q--){
            scanf("%d%d",&l,&r);
            for(int i = 0;i<26;i++){
                if(num[r][i] - num[l-1][i] > 0){
                    printf("%d\n",num[r][i] - num[l-1][i]);
                    break;  
                } 
            } 
        }
    }
}

猜你喜欢

转载自blog.csdn.net/Lj_victor/article/details/81590704