第十八届同济大学程序设计竞赛暨高校网络友谊赛 E、不平衡的字符串

-- 原题解

题链

-- 对于化简后的式子的理解

p[i] 是下标 i 之前有多少个与当前询问字母相同的字母;

将 ai-bp[i] 记为式子① ,将 ci-dp[i] 记为式子②;

为这两个式子构建两颗权值树状数组一二;

对于每一个新加入的 p[i],用式子②计算权值val2插入到第二颗树状数组中,先查找第二颗树状数组中查找 <= val2 的值有多少,即为满足条件②的以 i 为结尾的子段个数;

对于每一个新加入的 p[i],用式子①计算权值val1插入到第一颗树状数组中,再查找第一颗树状数组中查找 <= val1 的值有多少,即为不满足条件①的以 i 为结尾的子段个数;

因为满足条件②的一定包含(满足或不满足)条件①的个数,所以两者相减就是 满足①②的 以 i 为结尾的字段数量;

--代码

#include <bits/stdc++.h>
using namespace std;
#define ls rt<<1
#define rs rt<<1|1
#define LL long long
#define PI acos(-1.0)
#define eps 1e-8
#define Pair pair<double,double>
// notice
#define mod 1000000007
#define MAXN 1e18
#define MS 50009
 
LL n,m;
char s[MS]; 
LL qz[MS];
LL ab[MS];
LL cd[MS];
LL tp[MS],tot;
LL p[3][MS];

LL lowbit(LL x){
	return x&(-x);
}

void add(LL rt,LL pos,LL val){
	for(;pos<=n;pos+=lowbit(pos)){
		p[rt][pos] += val;
	}
}

LL query(LL rt,LL pos){
	LL ans = 0;
	for(;pos;pos-=lowbit(pos)){
		ans += p[rt][pos];
	}
	return ans;
}

int main() {
	ios::sync_with_stdio(false);
	cin >> n;
	cin >> s+1;
	cin >> m;
	LL ans = 0;
	while(m--){
		char vs;
		LL a,b,c,d;
		cin >> vs >> a >> b >> c >> d;
		for(int i=1;i<=n;i++){
			qz[i] = qz[i-1] + (s[i] == vs);
		}
		//-- a*i - b*qz[i] 离散化 
		for(int i=0;i<=n;i++){
			ab[i] = a*i - b*qz[i];
			tp[i] = ab[i];
		}
		sort(tp,tp+n+1);
		tot = 0;
		for(int i=1;i<=n;i++){
			if(tp[i] != tp[i-1]) tp[++tot] = tp[i];
		}
		for(int i=0;i<=n;i++){
			ab[i] = lower_bound(tp,tp+tot+1,ab[i]) - tp + 1;
		}
		//-- c*i - d*qz[i] 离散化
		for(int i=0;i<=n;i++){
			cd[i] = c*i - d*qz[i];
			tp[i] = cd[i];
		}
		sort(tp,tp+n+1);
		tot = 0;
		for(int i=1;i<=n;i++){
			if(tp[i] != tp[i-1]) tp[++tot] = tp[i];
		}
		for(int i=0;i<=n;i++){
			cd[i] = lower_bound(tp,tp+tot+1,cd[i]) - tp + 1;
		}
		//--
		for(int i=0;i<=n;i++) p[1][i] = p[2][i] = 0;
		for(int i=0;i<=n;i++){
			add(1,ab[i],1);
			add(2,cd[i],1);
			LL t2 = query(2,cd[i]);
			LL t1 = query(1,ab[i]);
			ans += t2-t1;
		}
	}
	cout << ans << "\n";
	

	return 0;
}

posted @ 2021-05-25 15:38  棉被sunlie  阅读(83)  评论(0)    收藏  举报