ABC 261 覆盤

2020luke發表於2024-05-12

ABC 261 覆盤

[ABC261A] Intersection

思路解析

因為這題czl錯了所以我特地來寫個覆盤

可以想到兩條線段的關係只有不相交,相交,包圍三種,於是我們可以直接判斷每種情況然後輸出就好了,可以在判斷前先將兩條線段的位置判斷一下交換方便之後操作。

#include<bits/stdc++.h>
using namespace std;
int l1, r1, l2, r2;
signed main() {
	cin >> l1 >> r1 >> l2 >> r2;
	if(l1 > l2) swap(l1, l2), swap(r1, r2);
	if(r1 >= r2) cout << r2 - l2;
	else if(r1 >= l2) cout << r1 - l2;
	else cout << 0;
	return 0;
}

[ABC261D] Flipping and Bonus

思路解析

是一個簡單 dp。用 \(f_{i,j}\) 表示現在是第 \(i\) 輪拋硬幣,計數器上的數是 \(j\),同時設 \(t_{C_i}=Y_i\)。分為兩種情況轉移;若當前硬幣為正面,則 \(f_{i,j} \gets f_{i-1,j-1}+X_i+t_j\);若當前硬幣為反面,則 \(f_{i,0} \gets f_{i-1,j}\)

最後注意判斷轉移時傳過來的元素是否有值。

code

#include<bits/stdc++.h>
#define int long long
#define PII pair<long long, long long>
#define fir first
#define sec second
using namespace std;
const int N = 5010;
int n, m, c[N], f[N][N];
PII s[N];
map<int, int> mp;
signed main() {
	memset(f, -1, sizeof(f));
	cin >> n >> m;
	for(int i = 1; i <= n; i++) cin >> c[i];
	for(int i = 1; i <= m; i++) {
		cin >> s[i].fir >> s[i].sec;
		mp[s[i].fir] = s[i].sec;
	}
	f[0][0] = 0;
	for(int i = 1; i <= n; i++) {
		for(int j = 0; j <= n; j++){
			if(f[i - 1][j] >= 0) f[i][0] = max(f[i][0], f[i - 1][j]);
			if(j > 0 && f[i - 1][j - 1] >= 0) f[i][j] = max(f[i][j], f[i - 1][j - 1] + c[i] + mp[j]);
		}
	}
	int ans = 0;
	for(int i = 0; i <= n; i++) ans = max(ans, f[n][i]);
	cout << ans;
	return 0;
}

[ABC261E] Many Operations

思路解析

首先可以發現,如果直接跑肯定會炸,於是考慮最佳化。首先發現操作有很多重複的,所以可以考慮把每一個數經過所有操作後的值都預處理下來,但這樣顯然空間也會炸。然後我們又想到可以不需要求下每個數經過操作後的值,可以把每一位二進位制上在開始前是 \(0\) 還是 \(1\) 的情況記錄下來,然後在需要查詢時遍歷每一位,把每一位上對應二進位制的值取出來再相加即可。

還有就是儘量不要用我的程式碼的實現去寫,看上去十分醜陋不便於除錯,可以直接用 bitset 或整形變數儲存,沒必要使用 dp。

code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 10;
int n, c;
int f[2][N][32];
signed main() {
	cin >> n >> c;
	for(int i = 0; i <= 30; i++) f[1][0][i] = 1;
	for(int i = 1, op, x; i <= n; i++) {
		cin >> op >> x;
		for(int j = 0; j <= 30; j++) {
			int t = ((x >> j) & 1);
			for(int k = 0; k < 2; k++) {
				if(op == 1) f[k][i][j] = f[k][i - 1][j] & t;
				else if(op == 2) f[k][i][j] = f[k][i - 1][j] | t;
				else if(op == 3) f[k][i][j] = f[k][i - 1][j] ^ t;
			}
		}
		int res = 0;
		for(int j = 0; j <= 30; j++) {
			int t = ((c >> j) & 1);
			res += (f[t][i][j] << j);
		} c = res;
		cout << res << '\n';
	}
	return 0;
}

[ABC261F] Sorting Color Balls

思路解析

首先我們可以考慮如果沒有 \(C\) 的情況下那答案就是 \(X\) 中逆序對的個數。接下來想如果加入了 \(C\),那答案減去的部分的每個逆序對 \((i,j)\),都有 \(C_i=C_j\);也就是說,只有對於 \(C_i=C_j\) 的數對 \((i,j)\) 才有可能對答案造成貢獻;而同時,只有 \(X_i>X_j\) 才會對答案造成貢獻,所以我們只需要對於每一個 \(C_{d_1}=C_{d_2}=C_{d_3}\dots\) 求序列 \(W_{d_1},W_{d_2},W_{d_3}\dots\) 的逆序對數即可。

求逆序對的方法很多,這裡我用的是樹狀陣列法,記得要在每次求完逆序對後撤銷原來的操作。

code

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
namespace BIT {
	const int B_SIZE = 5e5 + 10;
	int B[B_SIZE + 10];
	void add(int x, int y) {
		for(; x <= B_SIZE; x += (x & -x)) B[x] += y;
	}
	int ask(int x) {
		int sum = 0;
		for(; x > 0; x -= (x & -x)) sum += B[x];
		return sum;
	}
}
using namespace BIT;
int n, c[N], d[N];
vector<int> v[N];
long long nxd(int x) {
	long long res = 0;
	for(auto it : v[x]) {
		res += ask(n + 1) - ask(it);
		add(it, 1);
	} 
	for(auto it : v[x]) add(it, -1);
	return res;
}
signed main() {
	cin >> n;
	for(int i = 1; i <= n; i++) cin >> c[i];
	for(int i = 1; i <= n; i++) cin >> d[i];
	long long ans = 0;
	for(int i = 1; i <= n; i++) {
		ans += ask(n + 1) - ask(d[i]);
		add(d[i], 1);
	}
	for(int i = 1; i <= n; i++) add(d[i], -1);
	for(int i = 1; i <= n; i++) v[c[i]].push_back(d[i]);
	for(int i = 1; i <= n; i++) ans -= nxd(i);
	cout << ans;
	return 0;
}

相關文章