AtCoder Beginner Contest 346 G

XiaoMo247發表於2024-04-01

# G - Alone (atcoder.jp)

ABC 346 這一場來說相對比較簡單,F是一個細節比較多的二分,G也算是一個比較板子的題。

簡單說一下 G 題的思路。

其實比較容易想到用兩個陣列維護第 i 個數 \(a_i\) 在第 i 位之前出現的位置,以及第 i 個數在第 i 位之後出現的位置。那麼當前位的能夠滿足的區間就為 \((i - last_i) * (next_i - i)\)

image-20240401212122423

但是每一位都這樣算會有重複,我們考慮一下如何去重。

對於第一組樣例:

5
2 2 1 2 1

image-20240401212226782

我們發現相乘的本質實際上與分佈原理有一定關係,於是把對應的區間畫出來。

image-20240401212341024

可以得到上圖,我們再聯絡一下,從兩個不同區間選兩個數的方案數等於兩個不同區間元素個數乘積,畫圖即矩形的面積。

image-20240401212551054

會發現所有矩形的並的面積即是答案,不難想到掃描線演算法。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN = 5e5+5;
ll X[MAXN], n, ans, a[MAXN];
ll l[MAXN];
ll last[MAXN], nxt[MAXN];
struct line{
	ll x1, x2, y;
	ll tag;
}L[MAXN];
bool operator < (line xx, line yy){
	return xx.y < yy.y;
}
struct node{
	ll l, r;
	int cnt, len;
}tr[MAXN << 3];
void build(ll x, ll l, ll r){
	tr[x] = {l, r, 0, 0};
	if(l == r) return;
	ll mid = l + r >> 1;
	build(x << 1, l, mid);
	build(x << 1 | 1, mid + 1, r);
}
void pushup(ll x){
	ll l = tr[x].l, r = tr[x].r;
	if(tr[x].cnt) tr[x].len = X[r + 1] - X[l];
	else tr[x].len = tr[x << 1].len + tr[x << 1 | 1].len;
}
void modify(ll x, ll l, ll r, ll w){
	if(tr[x].r < l || r < tr[x].l) return;
	if(l <= tr[x].l && tr[x].r <= r){
		tr[x].cnt += w;
		pushup(x);
		return;
	}
	modify(x << 1, l, r, w);
	modify(x << 1 | 1, l, r, w);
	pushup(x);
}
int main(){
	ios::sync_with_stdio(false);
	cin >> n;
	for(int i = 1; i <= n; i ++){
		cin >> a[i];
		last[i] = l[a[i]];
		nxt[l[a[i]]] = i;
		nxt[i] = n + 1;
		l[a[i]] = i;
	}
	for(int i = 1; i <= n; i ++){
		L[i] = {last[i], i, i, 1};
		L[n + i] = {last[i], i, nxt[i], -1};
		X[i] = last[i];
		X[n + i] = i;
	}
	n <<= 1;
	sort(L + 1, L + n + 1);
	sort(X + 1, X + n + 1);
	int len = unique(X + 1, X + n + 1) - (X + 1);//去重 因為從 1開始所以減 x+1
	build(1, 1, len - 1);
	unordered_map<ll, ll> mp;
	for(int i = 1; i <= len; i ++){
		mp[X[i]] = i;
	}
	for(int i = 1; i < n; i ++){
		modify(1, mp[L[i].x1], mp[L[i].x2] - 1, L[i].tag);
		ans += tr[1].len * (L[i + 1].y - L[i].y);
//		cout << L[i].y << endl;
	}
	cout << ans << endl;
	return 0;
}

相關文章