[CF Round #294 div2] D. A and B and Interesting Substrings 【Map】

题目链接:D. A and B and Interesting Substrings

题目大意

给定26个小写字母的权值,一共26个整数(有正有负)。

给定一个小写字母组成的字符串(长度10^5),求有多少长度大于1的子串满足:

1)首尾字符相同。

2)除了首尾字符外,其他字符的权值和为0。

题目分析

使用STL Map。开26个Map,给每个字母开一个。

先求出权值的前缀和 Sum[] 。

然后1到l枚举每一位字符,如果是a,那么 Ans += Map[a][Sum[i - 1]];

然后 ++Map[a][Sum[i]];

这个原理是十分简单的,但是我就是这么弱,以至于比赛的时候想不到,然后用了一种复杂的方法,最后WA了= =

时间复杂度 O(n log n) 。

代码

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

using namespace std;

inline int gmin(int a, int b) {return a < b ? a : b;}
inline int gmax(int a, int b) {return a > b ? a : b;}

typedef long long LL;
typedef unsigned long long ULL;

const int MaxL = 100000 + 5, MaxC = 26 + 5;

int l;
int V[MaxC], A[MaxL];

LL Ans;
LL Sum[MaxL];

char S[MaxL];

map<LL, int> Mp[MaxC];

int main()
{
	for (int i = 0; i < 26; ++i) scanf("%d", &V[i]);
	scanf("%s", S + 1);
	l = strlen(S + 1);
	for (int i = 1; i <= l; ++i) A[i] = S[i] - ‘a‘;
	Sum[0] = 0ll;
	Ans = 0ll;
	for (int i = 1; i <= l; ++i) Sum[i] = Sum[i - 1] + (LL)V[A[i]];
	for (int i = 0; i < 26; ++i) Mp[i].clear();
	for (int i = 1; i <= l; ++i)
	{
		Ans += (LL)Mp[A[i]][Sum[i - 1]];
		++Mp[A[i]][Sum[i]];
	}
	cout << Ans << endl;
	return 0;
}

  

时间: 2024-10-06 22:20:22

[CF Round #294 div2] D. A and B and Interesting Substrings 【Map】的相关文章

Codeforces Round #294 Div2 D(A and B and Interesting Substrings)

Problem 给一个长度为N的字符串S,字符集是[a,z],每个字符都有一个权值Vi,求有多少个子串subS满足以下条件: 1. |subS|>=2 2. subS[0]=subS[|subS|?1] 3. ∑|subS|?2i=1Vi=0 Limits TimeLimit(ms):2000 MemoryLimit(MB):256 N∈[1,105] Vi∈[?105,105] Look up Original Problem From here Solution 如果没有条件2,用前缀和思想

Codeforces Round #294 Div2 E(A and B and Lecture Rooms)

Problem 给一棵树,含有N个节点,N?1条边.进行M次查询,每次给定两个节点x,y,问树上有多少个节点到x,y的距离相同. Limits TimeLimit(ms):2000 MemoryLimit(MB):256 N,M∈[1,105] x,y∈[1,N] Look up Original Problem From here Solution 求出a,b两个节点的lca,再找到lca?>a或lca?>b上的某个节点v使得dis(v,a)=dis(v,b).分v=lca,v∈lca?&g

【CF】Round #618 div2 C(文末有技巧)

目录 round #618 div2 C(文末有技巧) 题目: 样例输入输出 思路 小技巧(拿小本本记下来) round #618 div2 C(文末有技巧) 这是题目链接->链接 题目: 原题目是全英文的,所以我就粗略来翻译一下: 有这样一个函数f:f(x,y)=(x|y)-y;(其中|是按位或操作) 比如说:f(11,6)=(11|6)-6=15-6=9;(简单明了) 现在有一个数组 [a1,a2,-,an],让你求f(f(-f(f(a1,a2),a3),-an?1),an) ,数组中可能有

codeforces round #257 div2 C、D

本来应该认真做这场的,思路都是正确的. C题,是先该横切完或竖切完,无法满足刀数要求,再考虑横切+竖切(竖切+横切), 因为横切+竖切(或竖切+横切)会对切割的东西产生交叉份数,从而最小的部分不会尽可能的大. 代码如下,虽然比较长.比较乱,但完全可以压缩到几行,因为几乎是4小块重复的代码,自己也懒得压缩 注意一点,比如要判断最小块的时候,比如9行要分成2份,最小的剩下那份不是9取模2,而应该是4 m/(k+1)<=m-m/(k+1)*k          #include<bits/stdc+

codeforces Round #250 (div2)

a题,就不说了吧 b题,直接从大到小排序1-limit的所有数的lowbit,再从大到小贪心组成sum就行了 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #define N 200000 6 using namespace std; 7 int pos[N],a[N],s[N],f[N],la[N],b[N],i,j,k,ans,n,p

Codeforces Round#320 Div2 解题报告

Codeforces Round#320 Div2 先做个标题党,骗骗访问量,结束后再来写咯. codeforces 579A Raising Bacteria codeforces 579B Finding Team Member codeforces 579C A Problem about Polyline codeforces 579D "Or" Game codeforces 579E Weakness and Poorness codeforces 579F LCS Aga

Codeforces Round #254(div2)A

很有趣的题.想到了就非常简单,想不到就麻烦了. 其实就是一种逆向思维:最后结果肯定是这样子: WBWBWBWB... BWBWBWBW... WBWBWBWB... ... 里面有“-”的地方改成“-”就行了. 但是我开始是正着想的,想每个点怎么处理,这还要看它周围点的状态,越想越麻烦... 这题中体现的正难则反的逆向思维很值得学习. #include<iostream> #include<cstdio> #include<cstdlib> #include<cs

Codeforces Round #254(div2)B

就是看无向图有几个连通块,答案就是2n-num. 范围很小,就用矩阵来存图减少代码量. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<map> #include<set> #include<vector> #include<algorithm> #inc

Codeforces Round #260(div2)C(递推)

有明显的递推关系: f[i]表示i为数列中最大值时所求结果.num[i]表示数i在数列中出现了几次. 对于数i,要么删i,要么删i-1,只有这两种情况,且子问题还是一样的思路.那么很显然递推一下就行了:f[i]=max(f[i-1],f[i-2]+i*num[i]); 这里技巧在于:为了防止麻烦,干脆就所有数的出现次数都记录一下,然后直接从2推到100000(类似于下标排序),就不用排序了,也不用模拟删除操作了.这一技巧貌似简单,但实际上临场想出来也需要点水平. #include<iostrea