cf519D . A and B and Interesting Substrings 数据结构map

题意:

已知26个小写字母有各自的权值(正,负,或0)

现在给出一个字符串,长度<=1e5

问这个字符串有多少个子串满足:

开头的字母和结尾的字母一样

字符串除了开头和结尾的字母外,其余的字母的权值和为0

本来是一道水题,一看就知道大体的思路了,结果硬是搞了一个多小时

先是用set,发现超时了,改为用map

思路:

1.我们先预处理这个字符串的权值的前缀和

sum[i]表示从字符串的起点到i的权值和

2.我们要找到的子串,设以l开头和r结尾,则有

str[r] == str[l] 和 sum[r-1] - sum[l] == 0

即:sum[r] - sum[l] == val[str[r] - 'a']

那么我们只要记录:

(char,sum)以0为开头,char为结尾,权值和为sum的子串的个数即可

实现:用一个map

遍历一遍字符串,对于每一个(char,sum),找到前面出现多少(char,sum-val[char-'a'])

然后更新res,并且map[(char,sum)]++

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <set>
#include <map>
#include <cstdlib>

#define LL long long
#define fir first
#define sec second

using namespace std;

int val[26];
LL sum[100000+5];
char str[100000+5];

map< pair<char,LL>,int > ms;
map< pair<char,LL>,int > :: iterator it;

void solve()
{
    for(int i=0;i<26;i++){
        scanf("%d",&val[i]);
    }
    scanf("%s",str);
    int len = strlen(str);

    ms.clear();
    LL res = 0;
    sum[0] = 0;

    for(int i=1;i<=len;i++){
        sum[i] = sum[i-1] + val[str[i-1] - 'a'];
    }
    
    pair<char,LL> pr;
    LL tmp;
    for(int i=1;i<=len;i++){
        pr = make_pair(str[i-1],sum[i]);
        it = ms.find(make_pair(pr.fir,pr.sec - val[pr.fir-'a']));
        if(it != ms.end())
            res += it->sec;
        ms[pr]++;
    }

    //printf("%lld
",res);
    printf("%I64d
",res);
    return ;
}

int main()
{
    solve();
    return 0;
}
原文地址:https://www.cnblogs.com/-maybe/p/5055893.html