UPC OJ 一道水题 STL

Problem C: 字符串游戏

Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 10  Solved: 3 [Submit][Status][Web Board]

Description

说到游戏,大家还是比较喜欢的,但是玩游戏,如果想赢得对方还是得靠思维的,xy比较喜欢字符串,尤其是起始字母等于终止字母这样的字符串(the string's length must exceed one),但是呢,xy有个癖好,喜欢把每个字符重新分配一个值,喜欢的字符给非负数,不喜欢的字符给负数。但是,xy比较喜欢数字0,所以,他决定找到一个字符串中有多少个字串满足起始字母等于终止字母,且除了起始字母和终止字母外其他字母的和为0。但是xy最近比较忙,希望你能帮助他。

Input

第一行包含26个整数xi,xi属于[-100000,100000],非别代表着小写字母a,b,c,....,z的值。

第二行一个只包含小写字母的字符串,长度你自己猜,算了,给你个范围,length between 1 and 100000.

Output

输出答案,每个答案占一行。

Sample Input

1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 8 1 1 1 1 1 1
xabcab

Sample Output

2

题目分析:

每种字母的字符串求一遍,预处理前缀和,每次查找到一个位置i,查询前面有多少与sum[i-1]相同的以该子母为结尾的sum[j],用mp实现,总复杂度O(nlogn)
刚开始用了multiset中的count函数,总是超时,最后据我推断,那是因为count函数的时间复杂度是O(klogn),k是相同的个数,唉,还是太年轻。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<iostream>
#include<cstdlib>
#include<queue>
#include<map>
using namespace std;
typedef long long LL;
char s[100005];
LL a[26],sum[100005];
map<LL,int>mp;
vector<int>b[26];
int main()
{
    for(int i=0; i<26; ++i)
        scanf("%lld",&a[i]);
    scanf("%s",s+1);
    int len=strlen(s+1);
    sum[0]=0;
    long long ans=0;
    for(int i=1; i<=len; ++i)
    {
        int c=s[i]-'a';
        sum[i]=sum[i-1]+a[c];
        b[c].push_back(i);
    }
    for(int i=0; i<26; ++i)
    {
        mp.clear();
        for(int j=0; j<b[i].size(); ++j)
        {
            if(j>0)ans+=mp[sum[b[i][j]-1]];
            mp[sum[b[i][j]]]++;
        }
    }
    printf("%lld
",ans);
    return 0;
}
 
 
 
/**************************************************************
    Problem: 3285
    User: 1407010221
    Language: C++
    Result: Accepted
    Time:204 ms
    Memory:2956 kb
****************************************************************/
View Code



原文地址:https://www.cnblogs.com/shuguangzw/p/5023735.html