NOIP2023 国庆集训 A 组 Day2

T1

思路:记字母对(l,r),考虑一个字母对(p,q),我们可以统计l在p的左边,r在p,q之间的字母对,也就是左端点l在p左边与该字母对交叉的个数,这样就不会算重。

从左到右扫描字符串,开两个树状数组,第一个以l为下标,第二个以r为下标,一个字母对(p,q)的答案即为第一个树状数组中[1--p - 1]的字母对数量减去第二个树状数组中[1--p - 1]的字母对数量。

AC代码

#include <bits/stdc++.h>

using namespace std;
char s[100001];
int now[26][2],n,tr[2][100001];
long long ans;
bool vis[26];
void update(int x, int y, int op) {
    for (;x <= n;x += (x & (-x))) tr[op][x] += y;
}
int query(int x,int op){
	int ans = 0;
	for(;x;x -= (x & (-x))) ans += tr[op][x];
	return ans;
}
int main(){
	scanf("%s",s + 1);
	n = strlen(s + 1);
	for(int i = 1;i <= n;i++){
		int id = s[i] - 'a';
		if(vis[id]){
			now[id][1] = i;
			vis[id] = 0;
			ans += query(now[id][0] - 1,0) - query(now[id][0] - 1,1);
			update(now[id][0],1,0);
			update(now[id][1],1,1); 
		}
		else{
			vis[id] = 1;
			now[id][0] = i;
		}
	}
	cout << ans;
	return 0;
}

T2

 

posted @ 2023-10-04 20:49  LouYW07  阅读(17)  评论(0)    收藏  举报