备战蓝桥杯 Day5 前缀和

前缀和(区间求和快)

1.要点

[[前缀和]]

a[0]=0,prefix[0]=0;
for(int i=1;i<=n;i++){
	prefix[i]=prefix[i-1]+a[i];
}
sum(l,r)=prefix[r]-prefix[l-1];

重点:
前缀和:预处理算法,a为静态数组,即在区间和查询过程中不会进行修改
差分:先区间修改,再区间查询
树状数组或线段树:一边修改,一边查询

2.题目

2020子串分值和

思路:
跟前缀和没啥关系,暴力两层遍历+map哈希能拿一些分,得满分要用last数组记录每个字母上一次出现位置,然后遍历一次字符串(字符串之前先加个空格),每个字母左边到l[i]+1,保证第一次出现,共i-l[i]种情况,右边到n,共n-i+1种情况,两侧互相独立,相乘即可
代码如下:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N=1e5+9;
int l[N],p[26];

int main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	string s;
	getline(cin,s);
	//下面两个顺序不能反 
	int n=s.size();
	s=" "+s;
	ll res=0;
	for(int i=1;i<=n;i++){
		int t=s[i]-'a';
		l[i]=p[t];
		p[t]=i;
	}
	for(int i=1;i<=n;i++){
		//左边到last[i]+1,共i-last[s[i]]种可能,右边到n,共n-i+1种可能 
		res+=(ll)(i-l[i])*(n-i+1);
	}
	cout<<res;
	return 0;
}
2020子串分值

![[字母贡献度.png]]本质为上面字母贡献度,子串分值和为右侧为n的特殊情况,本题右侧没有字母则为n+1,需要预处理每个位置字母的左右边界,和前缀和类似
代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N=1e5+9;
int l[N],r[N],p[26];

int main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	string s;
	getline(cin,s);
	int n=s.size();
	s=" "+s;
	ll res=0;
	for(int i=1;i<=n;i++){
		int t=s[i]-'a';
		l[i]=p[t];//l[i]为对于s[i],左侧相同字母出现位置,若没有则为0 
		p[t]=i;//更新位置 
	}
	for(int i=0;i<26;i++)	p[i]=n+1;//r[s[i]]没有则为n+1 
	for(int i=n;i>=1;i--){
		int t=s[i]-'a';
		r[i]=p[t];//r[i]为对于s[i],右侧相同字母出现位置,若没有则为n+1 
		p[t]=i;//更新位置 
	}
	for(int i=1;i<=n;i++){
		res+=(ll)(i-l[i])*(r[i]-i);//只考虑单个字母出现一次的左边界与右边界,乘法原理 
	}
	cout<<res;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值