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;
}