Codeforces Round #294 (Div. 2) D. A and B and Interesting Substrings
题目链接:http://codeforces.com/contest/519/problem/D
题目意思这里就不说了,最主要的思想就是:先预处理,把所有的相同的字母的位置放在一起,然后从前往后遍历(从后往前也可以)这些位置,每次统计与这个位置的前一个位置的前缀和的值相等的字母的数量。可以用二分,不过直接用map简单多了。不过还是想说CF最喜欢卡long long,但我还是因为这个WA了好几次。。。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<map> using namespace std; typedef long long INT; const int maxn = 100010; struct node { int c,l; }T[26][maxn]; INT w[30],A[maxn]; char str[maxn]; map<INT,INT> mp; int main() { while(scanf("%lld",&w[0])!=EOF) { for(int i = 1;i < 26;++i) scanf("%lld",&w[i]); scanf("%s",str); memset(A,0,sizeof(A)); int len = strlen(str); A[0] = w[str[0]-'a']; for(int i = 1;i < len;++i) A[i] = A[i-1] + w[str[i]-'a']; memset(T,0,sizeof(T)); memset(T,0,sizeof(T)); for(int i = 0;i < len;++i) { T[str[i]-'a'][0].l++; T[str[i]-'a'][T[str[i]-'a'][0].l].l = i; //把所有的相同的字母的位置放在一起 } INT ans = 0; for(int i = 0;i < 26;++i) if(T[i][0].l > 1) { mp.clear(); for(int j = 1;j <= T[i][0].l;++j) { if(T[i][j].l > 0) ans += mp[A[T[i][j].l-1]]; //统计这个位置的前一个位置的前缀和的值在前面出现的次数 mp[A[T[i][j].l]]++; } } printf("%lld\n",ans); } return 0; }