repkironca
I was born again because of love, but died of the same reason.
可以用來監督建電學術水了多久
有個叫蘇昱亘的人,為了考上嚮往已久的建電學術,在 IG 中發誓,要每天 AC 一題算法題。
在茶會執秘、寒訓執秘、雙暑訓摧殘、備課、學業壓力等種種種因素下,毫無懸念的失敗了。
同時,他發現在 IG 發現動,告訴大家自己 AC 了什麼題目,除了顯現自己有多弱外,在眾電神前根本是關公面前耍大刀。
Legend Never Dies.
雖然他不見得有時間再每天刷題了
不過他會把遇到的有趣題目
全部放到這邊來
首先,會有人特地來翻我主頁,並找到這裡,我還滿開心的,祝你打扣愉快。
基本上,這邊會有 AC 扣、題目連結、心得、分類、嘴砲,偶而摻雜一些毫無相關的東西,講更白就是我直接把這裡當日記寫。
我之所以沒公開分享這份簡報,就是因為裡面的內容非常不成熟,而且我根本沒要認真寫題解的意思,更像是自己打自己爽。所以當成小丑觀察就好,不用太期待能從中獲得什麼收獲。
DP、LIS、sort
2021 Jan. APCS #4
你有一張 n * n 的圖
圖上有 y 個點,位置不重複
以左下角為 (0, 0),上、右為正向
今從 (0, 0) 出發,只能往右或上走
求最多可經過多少個點
1 <= n <= 1e7
1 <= y <= 2e5
#include <bits/stdc++.h>
#define gura ios_base::sync_with_stdio(false), cin.tie(0);
#define pii pair <int, int>
#define F first
#define S second
using namespace std;
vector <pii> location;
const int MAXN = 2e5 + 17;
bool cmp (pii a, pii b){
if (a.F < b.F) return true;
if (a.F > b.F) return false;
if (a.S < b.S) return true;
return false;
}
vector <int> lis;
void solve (){
int border_size; cin >> border_size;
while (border_size--){
int x, y; cin >> x >> y;
location.push_back({x, y});
}
sort(location.begin(), location.end(), cmp);
lis.push_back(location[0].S);
for (int i = 1; i < location.size(); i++){
if (location[i].S >= lis.back()) lis.push_back(location[i].S);
else{
auto to = upper_bound(lis.begin(), lis.end(), location[i].S);
*to = location[i].S;
}
}
cout << lis.size() << '\n';
}
int main (){
gura
solve();
}
實作、vector、pointer
2016 Oct. APCS #4
指令有以下幾種:
nB,n 壘打,所有人移動 n 格
HR,全壘打,就是四壘打
others,全部都是出局,誰鳥他
-每有一人回到本壘則得 1 分
-每累計 3 個 out,壘包清空
-求總計 r 個 out 時的得分
-輸入有 10 行,最後一行為 r,其 它是打擊資料,要直的讀
#include <bits/stdc++.h>
#define gura ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define vecs vector <string>
#define hit source[index_m][index_h]
using namespace std;
int tar, total_out = 0, tmp_out = 0;
int score = 0;
vector <vecs> source(10);
vector <int> field;
void update(){
sort(field.begin(), field.end());
while(!field.empty()){
if (field.back() >= 4){
score++;
field.pop_back();
}else{
break;
}
}
// for (auto to:field) cout << to << ' ';
// cout << "score = " << score << '\n';
}
void solve(){
for (int i = 1; i <= 9; i++){
int tmp; cin >> tmp;
while(tmp--){
string str; cin >> str;
source[i].push_back(str);
}
}
cin >> tar;
int index_m = 1, index_h = 0;
while (total_out < tar){
int run = 0;
if (hit == "1B") run = 1;
else if (hit == "2B") run = 2;
else if (hit == "3B") run = 3;
else if (hit == "HR") run = 4;
else{
total_out++;
tmp_out++;
}
if (run != 0){
for (int i = 0; i < field.size(); i++){
int *to = &field[i];
*to += run;
}
field.push_back(run);
update();
}else if (tmp_out >= 3){
// cout << "clear field.\n";
field.clear();
tmp_out = 0;
}
if (index_m < 9) index_m++;
else{
index_m = 1;
index_h++;
}
}
cout << score << '\n';
}
int main (){
gura
solve();
}
BST、二元樹遍歷、sort
在 worst case 下
二元搜尋樹做 N 次 insert
最高複雜度為 O ( N 2 )
倘若你已經知道所有數字
要被 insert 的順序
求這棵 BST 中序遍歷之結果
1 <= N <= 1e6
- 1e30 <= num <= 1e30
#include <bits/stdc++.h>
#define gura ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ll long long int
using namespace std;
vector <ll> tmp;
int main (){
gura
int N; cin >> N;
while(N--){
ll temp; cin >> temp;
tmp.push_back(temp);
}
sort(tmp.begin(), tmp.end());
for (auto to:tmp) cout << to << ' ';
cout << '\n';
}
純觀念 超級水
BST 的中序遍歷
就是所有數字的遞增數列
BFS、dijkstra algorithm
這題到現在還是爛的,有路人要幫我 de 嗎
你有一張二維的圖 邊長上限 1e3
上面有個起點與終點
另外有 n 格是道路
每格道路都有自己的難度
當玩家經過難度為 x 的道路時
若本身等級為 y
則須將等級提升至 x
求從起點走到終點
所需的最小等級
#include <bits/stdc++.h>
using namespace std;
#define gura ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define INF 1e9 + 17
#define pq priority_queue
#define pii pair <int, int>
#define pipii pair <int, pii>
#define ll long long int
#define F first
#define S second
const int MAXN = 1e3 + 17;
int tmp_ans[MAXN][MAXN];
bool enter[MAXN][MAXN] = {false};
pq <pipii, vector <pipii>, greater<pipii>> waiting;
void solve (){
int length, width; cin >> length >> width;
for (int i = 0; i <= length; i++)
for (int j = 0; j <= width; j++)
tmp_ans[i][j] = INF;
int srt_x, srt_y, tar_x, tar_y; cin >> srt_y >> srt_x >> tar_y >> tar_x;
enter[srt_y][srt_x] = true; enter[tar_y][tar_x] = true;
tmp_ans[srt_y][srt_x] = 1; tmp_ans[tar_y][tar_x] = 1;
int walkable_count; cin >> walkable_count;
while (walkable_count--){
int x, y, level; cin >> y >> x >> level;
enter[y][x] = true;
tmp_ans[y][x] = level;
}
waiting.push({0, {srt_y, srt_x}});
while (!waiting.empty()){
auto wt = waiting.top();
int w = wt.F, y = wt.S.F, x = wt.S.S;
//printf("location = {%d, {%d, %d}}\n", w, y, x);
if (y+1 < length && enter[y+1][x]){
if (y+1 == tar_y && x == tar_x){
cout << w << '\n';
return;
}
if (tmp_ans[y+1][x] > w) waiting.push({tmp_ans[y+1][x], {y+1, x}});
else waiting.push({w, {y+1, x}});
enter[y+1][x] = false;
}
if (y-1 > -1 && enter[y-1][x]){
if (y-1 == tar_y && x == tar_x){
cout << w << '\n';
return;
}
if (tmp_ans[y-1][x] > w) waiting.push({tmp_ans[y-1][x], {y-1, x}});
else waiting.push({w, {y-1, x}});
enter[y-1][x] = false;
}
if (x+1 < width && enter[y][x+1]){
if (y == tar_y && x+1 == tar_x){
cout << w << '\n';
return;
}
if (tmp_ans[y][x+1] > w) waiting.push({tmp_ans[y][x+1], {y, x+1}});
else waiting.push({w, {y, x+1}});
enter[y][x+1] = false;
}
if (x-1 > -1 && enter[y][x-1]){
if (y == tar_y && x-1 == tar_x){
cout << w << '\n';
return;
}
if (tmp_ans[y][x-1] > w) waiting.push({tmp_ans[y][x-1], {y, x-1}});
else waiting.push({w, {y, x-1}});
enter[y][x-1] = false;
}
waiting.pop();
}
}
int main (){
gura
solve();
}
這還不是 AC CODE
unordered_map、recursion
AtCoder Beginner Contest Round 275 pD
定義一個數列如下
#include <bits/stdc++.h>
#define gura ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define unmap unordered_map
#define usll unsigned long long int
using namespace std;
unmap <usll, usll> dic;
usll f(usll num){
if (num == 0) return 1;
if (dic.count(num)) return dic[num];
dic[num] = f(num / 2) + f(num / 3);
return dic[num];
}
void solve (){
usll num; cin >> num;
cout << f(num) << '\n';
}
int main (){
gura
solve();
}
求數列第 i 項
unordered_set、vector
AtCoder Beginner Contest Round 274 pD
你有一個長度為 N 的向量集合 A
其中定義點 \(P_1\) 位於 (0, 0)
點 \(P_2\) 位於 (\(A_1\) , 0)
而終點是 \(P_{N+1}\)
從 \(P_2\) 開始
每個點 \(P_{i+1}\) 與上點距離
均為 \(A_{i}\)
且與上點的連線夾角須為 90 度
求終點是否可能落在
指定的點 (x, y)?
#include <bits/stdc++.h>
#define ic ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define pii pair <int, int>
#define ll long long int
#define F first
#define S second
#define pq priority_queue
#define usll unsigned long long int
using namespace std;
bool judge (int tar, vector <int> num){
unordered_set <int> exist;
exist.insert(0);
for (auto to:num){
unordered_set <int> tmp;
swap(exist, tmp);
for (auto au:tmp){
exist.insert(au + to);
exist.insert(au - to);
}
}
return exist.count(tar);
}
void solve (){
int N, tar_x, tar_y; cin >> N >> tar_x >> tar_y;
vector <int> num_x, num_y;
int first; cin >> first;
tar_x -= first;
for (int i = 2; i <= N; i++){
int tmp; cin >> tmp;
if (i&1) num_x.push_back(tmp);
else num_y.push_back(tmp);
}
if (judge(tar_x, num_x) && judge(tar_y, num_y)) cout << "Yes\n";
else cout << "No\n";
}
int main (){
ic
solve();
}
linked_list
#include <bits/stdc++.h>
#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
using namespace std;
struct node{ //linked list 的節點
int index = -1;
int group = -1; // 此點屬於哪個組別
node *next = nullptr;
};
const int MAXN = 1e6 + 17;
int self_group[MAXN] = {}; // self_group[index] = 第 index 個人所在組別,預設為 0
vector <node*> location(1017, nullptr); // 隊伍中的最後一個第 [group] 組的人在哪
vector <int> clear; // 拿來優化用的,我下回合初始化時要把誰歸零
struct linked_list{
node *root = nullptr, *end = nullptr;
int length = 0;
void dequeue (){
cout << root->index << '\n';
if (location[root->group] != nullptr){ // 若隊伍中有與 root 同組的人(廢話)
if (root->index == location[root->group]->index) // 若 root 自己就是該組的最後一個
location[root->group] = nullptr; // 那現在隊伍中沒有這組的人了
}
if (length > 1){
root = root->next;
}else{
root = nullptr;
end = nullptr;
}
length--;
//cout << "dequeue succeed\n";
}
void enqueue (int tar, int group){
node *tmp = new node;
tmp->index = tar;
tmp->group = group;
if (length == 0){
root = tmp;
end = tmp;
}
else if (location[group] == nullptr || location[group]->index == end->index){
// (up) 隊伍中不存在該隊伍的人 或 該隊伍的最後一個人就是排尾
end->next = tmp;
end = tmp;
}else{
node *last = location[group];
tmp->next = last->next;
last->next = tmp;
}
if (group != 0) location[group] = tmp; // 如果這個人是有組別的
length++;
//cout << "enqueue succeed\n";
}
};
void solve (){
int N; cin >> N;
for (int i = 1; i <= N; i++){
for (int j = 0; j < 1017; j++) location[j] = nullptr;
for (auto to:clear) self_group[to] = 0;
clear.clear(); //這行有夠微妙 XDD
linked_list list;
cout << "Line #" << i << '\n';
int group_count; cin >> group_count;
for (int j = 1; j <= group_count; j++){
int count; cin >> count;
for (int k = 0; k < count; k++){
int tmp; cin >> tmp;
self_group[tmp] = j; //沒被設定到的就預設為 0
clear.push_back(tmp);
}
}
int query_count; cin >> query_count;
while (query_count--){
string opr; cin >> opr;
if (opr == "DEQUEUE"){
list.dequeue();
}else{
int index; cin >> index;
list.enqueue(index, self_group[index]);
}
}
}
}
int main (){
icisc
solve();
}
最大測資有 20 筆,在第一行吃進。
每筆測資中會有 N 個 組別
組別中有若干個人
人數共有 M 個,都有自己的 index
現在對 list 有兩種操作,進行 Q 次:
(1) 把最前面的人 pop 掉,輸出其 index
(2) 加入 index = x 的人進隊伍,若隊伍中已有與
他同組者,他直接插隊隊伍中最後一個同組者
至後方,否則排到最後面
\(\forall\) N \(\leq\) 2000,M \(\leq\) 1000,Q \(\leq 2e5\)
vector、set
AtCoder Beginner Contest Round 278 pD
你有一個數列
然後現在有 3 種操作
1:把整個數列重製為 x
2:把第 t 個數字 + x
3:輸出第 t 個數字
對,就這樣,把操作做好
#include <bits/stdc++.h>
#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define pii pair <int, int>
#define ll long long int
#define F first
#define S second
#define pq priority_queue
#define usll unsigned long long int
using namespace std;
const int MAXN = 2e5;
ll judge[MAXN];
void solve (){
for (int i = 0; i < MAXN; i++) judge[i] = -1;
usll asi = -1;
vector <usll> num;
int N; cin >> N;
for (int i = 0; i < N; i++){
int tmp; cin >> tmp;
num.push_back(tmp);
}
int Q; cin >> Q;
while (Q--){
int opr; cin >> opr;
if (opr == 1){
int tmp; cin >> tmp;
asi = tmp;
}else if (opr == 2){
int tar, plus; cin >> tar >> plus;
if (asi != -1){
if (judge[tar-1] != asi){
num[tar-1] = asi;
judge[tar-1] = asi;
}
}
num[tar-1] += plus;
}else{
int tar; cin >> tar;
if (asi != -1){
if (judge[tar-1] != asi){
num[tar-1] = asi;
judge[tar-1] = asi;
}
}
cout << num[tar-1] << '\n';
}
}
}
int main (){
icisc
solve();
}
三分搜
AtCoder Beginner Contest Round 279 pD
#include <bits/stdc++.h>
#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ll unsigned long long
using namespace std;
ll A, B;
double f (ll take){
return (double) A/sqrt(1 + take) + (double) B*take;
}
void solve (){
cin >> A >> B;
ll l = 0, r = A / B;
while (r - l > 2){
ll ml = (l*2 + r) / 3;
ll mr = (l + r*2) / 3;
if (f(ml) < f(mr)) r = mr;
else l = ml;
}
cout << fixed << setprecision(8) << min({f(l), f(r), f((l+r)/2)}) << '\n';
}
int main (){
icisc
solve();
}
給定一函式
\(f(x) = \frac{A}{\sqrt{x+1}} + B\,x\)
求其最小值,誤差不得超過 \(10^{-6}\)
\(1 \leq A \leq 10^{18}\)
\(1 \leq B \leq 10^{18}\)
int f(int n){
//...
}
void find_(){
int l = 0, r = 1e9; // r 視情況調整
for (int i = 0; i < 2e5; i++){ //可選擇要做 n 次、或左右界差距小於某值停下之類
int ml = (2*l + r) / 3;
int mr = (l + 2*r) / 3;
if (f(ml) < f(mr)) l = ml; //令其是凸函數
else r = mr;
}
}
Vector
AtCoder Beginner Contest Round 289 pC
你有 \(M\) 個集合
每個集合中可能會有 \(K\) 個數字
數字範圍從 1 到 \(N\)
若每個集合
只有"使用"與"不使用"
則想得到一個全集合(1 到 \(N\))
共有多少種組合?
\(1 \leq N、M、K \leq 10\)
#include <bits/stdc++.h>
#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define pii pair <int, int>
#define ll long long int
#define F first
#define S second
#define pq priority_queue
#define usll unsigned long long int
#define pb push_back
using namespace std;
int N, M;
vector <set <int>> sets;
int ans = 0;
void dfs (vector <bool> exist, int ptr = 0, int exist_count = 0){
// printf("ptr = %d, exist count = %d\n", ptr, exist_count);
if (ptr == M){
// cout << "exist count = " << exist_count << '\n';
if (exist_count == N) ans++;
return;
}
dfs(exist, ptr+1, exist_count); // without me
for (auto to:sets[ptr]){
if (!exist[to]){
exist[to] = true;
exist_count++;
}
}
dfs(exist, ptr+1, exist_count); // with me
}
void solve (){
cin >> N >> M;
sets.resize(M);
for (int i = 0; i < M; i++){
int k; cin >> k;
while (k--){
int tmp; cin >> tmp;
sets[i].insert(tmp);
}
}
dfs(vector <bool> (M+17, false));
cout << ans << '\n';
}
int main (){
icisc
solve();
}
Data Structure、Greedy、sort、Difference Array Algorithm
#include <bits/stdc++.h>
#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ll long long int
#define usll unsigned long long int
#define pii pair <int, int>
#define F first
#define S second
#define pq priority_queue
#define pb push_back
using namespace std;
void solve (){
int N, M; cin >> N >> M;
vector <usll> vec(N);
for (auto &to:vec) cin >> to;
sort(vec.begin(), vec.end(), greater<int>());
vector <usll> predif(N, 0); // 計算出現次數
while (M--){
int l, r; cin >> l >> r;
l--;r--; // cuz input is 1-based
predif[l]++;
if (r+1 < N) predif[r+1]--;
}
vector <usll> tmp = predif; //差分做前綴和來還原
for (int i = 1; i < N; i++) tmp[i] += tmp[i-1];
// for (auto to:tmp) cout << to << ' ';
sort(tmp.begin(), tmp.end(), greater<int>());
usll count = 0;
for (int i = 0; i < N; i++) count += vec[i]*tmp[i];
cout << count << '\n';
}
int main (){
icisc
solve();
}
首先給你一個序列
接下來會有 M 次操作
每次操作選定範圍 [l, r]
將裡面的數字全部加起來
剛開始的序列,順序可以自由調整
aka 隨便你亂排
目的是盡可能讓做完所有操作後
得到的 總和 是最大值
求該值
binary exponential、mathematics
共有 T 筆測資,\(1 \leq T \leq 10^5\)
每筆測資包含一個正整數 \(N\)
\(N\) 之極值是驚人的 \(10^{12}\)
你可以自由地把 N 分成很多段
長度 \(\geq 1\) 的小段
令此筆測資的價值
是各小段長度的相乘結果
求每筆測資的最大價值
#include <bits/stdc++.h>
#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ll long long int
using namespace std;
const int MOD = 1e9 + 7;
ll Mod (ll n, ll m){
return (n+m) % m;
}
ll Mult (ll a, ll b, ll m){
return Mod(Mod(a, m) * Mod(b, m), m);
}
ll bipow (ll a, ll b, ll m){
if (b == 0) return 1;
if (b == 1) return a;
if (b&1) return Mult(a, bipow(a, b-1, m), m);
ll tmp = bipow(a, b/2, m);
return Mult(tmp, tmp, m);
}
void solve (){
int N; cin >> N;
while (N--){
ll num; cin >> num;
if (num == 1) cout << "1\n";
else if (num == 2) cout << "2\n";
else if (num == 3) cout << "3\n";
else if (num%3 == 0) cout << bipow(3, num/3, MOD) << '\n';
else if (num%3 == 1) cout << Mult(4, bipow(3, (num-4)/3, MOD), MOD) << '\n';
else cout << Mult(2, bipow(3, (num-2)/3, MOD), MOD) << '\n';
}
}
int main (){
icisc
solve();
}
區間 DP
#include <bits/stdc++.h>
#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ll long long int
#define usll unsigned long long int
#define pii pair <int, int>
#define F first
#define S second
#define pq priority_queue
#define pb push_back
using namespace std;
const int INF = 1e9 + 17;
void solve (){
int N; cin >> N;
vector <int> vec(N+17);
int dp[N+17][N+17];
for (int i = 0; i <= N; i++)
for (int j = 0; j <= N; j++)
dp[i][j] = 0;
for (int i = 1; i <= N; i++) cin >> vec[i];
//initialization
for (int i = 1; i+2 <= N; i++) dp[i][i+2] = vec[i]*vec[i+1]*vec[i+2];
for (int i = 3; i < N; i++){ //length - 1
for (int j = 1; j+i <= N; j++){
dp[j][j+i] = INF;
for (int k = j+1; k < j+i; k++){
dp[j][j+i] = min(dp[j][j+i],
dp[j][k] + dp[k][j+i] + vec[j]*vec[k]*vec[j+i]);
}
}
}
cout << dp[1][N] << '\n';
}
int main (){
icisc
solve();
}
你有 N 個湖泊,\(2 \leq N \leq 50\)
每個湖泊都有自己的大小
是一個不超過 100 的正整數
每次選擇 3 個相鄰湖泊
並且 吞噬 中間那個
此舉造成的 汙染值 乃三者大小相乘
你必須吞噬掉除端點外的所有湖泊
求造成的汙染最小值
greedy、two pointers
共有 T 筆測資,\(1 \leq T \leq 10^4\)
每筆測資包含
\(1 \leq n \leq 10^5\)
長度為 \(n\) 的 0/1 字串
你可以使用以下操作
每次為一組:
( 1 ) 選擇一個數字,將其加到另一個數字上
( 2 ) 移除原數字
求最少需要幾組操作
可使此字串不嚴格遞增
#include <bits/stdc++.h>
#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ll long long int
#define usll unsigned long long int
#define pii pair <int, int>
#define F first
#define S second
#define pq priority_queue
#define pb push_back
using namespace std;
void solve (){
int T; cin >> T;
while (T--){
int N; cin >> N;
vector <int> vec(N);
for (auto &to:vec) cin >> to;
int front = 0, back = N-1;
int count = 0;
while (true){
while (vec[front] == 0 && front < N) front++;
while (vec[back] == 1 && back >= 0) back--;
if (front >= back) break;
count++;
front++; back--;
}
cout << count << '\n';
}
}
int main (){
icisc
solve();
}
Dynamic Programming
AtCoder Beginner Contest Round 291 pD
#include <bits/stdc++.h>
#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ll long long int
#define usll unsigned long long int
#define pll pair <ll, ll>
#define F first
#define S second
#define pq priority_queue
#define pb push_back
using namespace std;
ll Mod (ll n, ll m){
return (n+m) % m;
}
ll Plus (ll a, ll b, ll m){
return Mod(Mod(a, m) + Mod(b, m), m);
}
const int MOD = 998244353;
void solve (){
int N; cin >> N;
vector <pll> vec(N);
for (auto &to:vec){
cin >> to.F;
cin >> to.S;
}
vector <vector <ll>> dp(N, vector <ll>(2, 0));
dp[0][0] = 1; dp[0][1] = 1;
for (int i = 1; i < N; i++){
if (vec[i].F != vec[i-1].F) dp[i][0] = Plus(dp[i][0], dp[i-1][0], MOD);
if (vec[i].F != vec[i-1].S) dp[i][0] = Plus(dp[i][0], dp[i-1][1], MOD);
if (vec[i].S != vec[i-1].F) dp[i][1] = Plus(dp[i][1], dp[i-1][0], MOD);
if (vec[i].S != vec[i-1].S) dp[i][1] = Plus(dp[i][1], dp[i-1][1], MOD);
}
cout << Plus(dp[N-1][0], dp[N-1][1], MOD) << '\n';
}
int main (){
icisc
solve();
}
給定 \(N\) 張卡片,排成一維直線
\(1 \leq N \leq 2×10^5\)
分別給予從 1 至 \(N\) 的編號
每張卡片的正面與背面都有數字
值域從 1 至 \(10^9\)
剛開始時每張卡均正面朝上
求共有幾種可能性
使得檯面上所有向上的數字
兩兩相鄰 皆不同
將答案模上 \(998244353\)
DFS
AtCoder Beginner Contest Round 292 pD
#include <bits/stdc++.h>
#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ll long long int
#define usll unsigned long long int
#define pii pair <int, int>
#define F first
#define S second
#define pq priority_queue
#define pb push_back
using namespace std;
vector <vector <int>> graph;
vector <bool> visited;
vector <pii> path;
vector <bool> visited_path;
int node_count = 0;
int edge_count = 0;
bool dfs(int pos){
// printf("In dfs, pos = %d\n", pos);
visited[pos] = true;
node_count++;
for (auto to:graph[pos]){
if (!visited_path[to]){
visited_path[to] = true;
edge_count++;
}
if (pos == path[to].F){
if (!visited[path[to].S]) dfs(path[to].S);
}else{
if (!visited[path[to].F]) dfs(path[to].F);
}
}
if (node_count == edge_count) return true;
return false;
}
void solve (){
int N, M; cin >> N >> M;
if (N != M){
cout << "No\n";
return;
}
graph.resize(N+17);
visited.resize(N+17, false);
path.resize(M+17);
visited_path.resize(M+17, false);
for (int i = 0; i < M; i++){
int a, b; cin >> a >> b;
path[i] = {a, b};
graph[a].pb(i);
graph[b].pb(i);
}
for (int i = 1; i <= N; i++){
if (!visited[i]){
node_count = 0;
edge_count = 0;
if (!dfs(i)){
cout << "No\n";
return;
}
}
}
cout << "Yes\n";
}
int main (){
icisc
solve();
}
給定 \(N\) 個點與 \(M\) 條邊
\(1 \leq N \leq 2×10^5,0 \leq M \leq 2×10^5\)
可能包含自環、不保證圖連通
求每個連通分量中
邊的數量是否雨點的數量相等
若全數符合輸出 "Yes"
否則輸出"No"
Union-find Algorithm
#include <bits/stdc++.h>
#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ll long long int
#define usll unsigned long long int
#define pii pair <int, int>
#define pipii pair <int, pii>
#define F first
#define S second
#define pq priority_queue
#define pb push_back
using namespace std;
vector <pipii> graph;
vector <int> endpos;
bool cmp (pipii a, pipii b){
return (a.F < b.F);
}
int findend (int a){
if (endpos[a] == -1) return a;
endpos[a] = findend(endpos[a]);
return endpos[a];
}
bool connect (int a, int b){
int tmp_1 = findend(a), tmp_2 = findend(b);
if (tmp_1 == tmp_2) return false;
endpos[tmp_1] = tmp_2;
return true;
}
void solve (){
int N, M; cin >> N >> M;
endpos.resize(N+17, -1);
for (int i = 0; i < M; i++){
int from, to, cost; cin >> from >> to >> cost;
if (from == to) continue;
graph.pb({cost, {from, to}});
}
sort(graph.begin(), graph.end(), cmp);
usll ans = 0;
int count = 0;
int index = 0;
// for (auto to:graph) cout << to.F << ' ' << to.S.F << to.S.S << '\n';
while (count < N-1 && index < M){ // 成立的道路恰是 N-1 條
if (connect(graph[index].S.F, graph[index].S.S)){
ans += graph[index].F;
count++;
}
index++;
}
cout << ans << '\n';
}
int main (){
icisc
solve();
}
給定 \(N\) 個點與 \(M\) 條邊
每條邊連結兩個點
且其花費 \(K\),K 為 int 內的正整數
求在任兩點都是連通(允許間接)
的前提下,最小花費為何
\(1 \leq N \leq 4000\)
\(1 \leq M \leq \frac{N\;(N-1)}{2}\)
two pointers
AtCoder Beginner Contest Round 294 pE
#include <bits/stdc++.h>
#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ll long long int
#define usll unsigned long long int
#define pii pair <int, int>
#define pulul pair <usll, usll>
#define F first
#define S second
#define pq priority_queue
#define pb push_back
using namespace std;
vector <pulul> vec_1, vec_2;
void solve (){
usll L, N, M; cin >> L >> N >> M;
vec_1.resize(N);
vec_2.resize(M);
for (auto &to:vec_1) cin >> to.F >> to.S;
for (auto &to:vec_2) cin >> to.F >> to.S;
usll ans = 0;
auto itr_1 = vec_1.begin(), itr_2 = vec_2.begin();
usll a = (*itr_1).S, b = (*itr_2).S;
while (itr_1 < vec_1.end() && itr_2 < vec_2.end()){
if ((*itr_1).F == (*itr_2).F) ans += min(a, b);
if (a < b){
b -= a;
itr_1++;
a = (*itr_1).S;
}else if (a > b){
a -= b;
itr_2++;
b = (*itr_2).S;
}else {
itr_1++;
a = (*itr_1).S;
itr_2++;
b = (*itr_2).S;
}
}
cout << ans << '\n';
}
int main (){
icisc
solve();
}
你有一個 \(2×L\) 的表格
\(1 \leq L \leq 10^{12}\),皆由 int 內正整數組成
求有多少組 同行之兩數字相同 的狀況
由於數字過大,輸入的方式比較特別
輸入共兩組,大小分別為 \(N_1、N_2\)
\(1 \leq N_1、N_2 \leq 10^5\)
代表第一與第二列的數字
每筆輸入包含 \(x、y\) 兩數字
代表 後面 \(y\) 個格子的數字皆為 \(x\)
Dynamic Programming
#include <bits/stdc++.h>
#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ll long long int
#define usll unsigned long long int
#define pll pair <ll, ll>
#define plpll pair <ll, pair <ll, ll>>
#define F first
#define S second
#define pq priority_queue
#define pb push_back
using namespace std;
const int MOD = 1e8+7;
ll Mod (ll a){
return (a+MOD) % MOD;
}
ll Plus (ll a, ll b){
return Mod(Mod(a) + Mod(b));
}
ll Minus (ll a, ll b){
return Mod(Mod(a) - Mod(b));
}
vector <vector <pll>> dp;
vector <vector <bool>> barrier;
vector <vector <bool>> gate;
void update (int i, int j){
if (i == 1 && j == 1) return;
dp[i][j].S = Minus(Plus(dp[i-1][j].S, dp[i][j-1].S), dp[i-1][j-1].S);
/*
if (gate[i-1][j]) dp[i][j].S = Plus(dp[i][j].S, dp[i-1][j].F);
if (gate[i][j-1]) dp[i][j].S = Plus(dp[i][j].S, dp[i][j-1].F);
if (gate[i-1][j-1]) dp[i][j].S = Minus(dp[i][j].S, dp[i-1][j-1].F);
*/
if (!barrier[i][j]){
dp[i][j].F = Plus(dp[i][j].F, Plus(dp[i-1][j].F, dp[i][j-1].F));
dp[i][j].F = Plus(dp[i][j].F, dp[i][j].S);
}
if (gate[i][j]) dp[i][j].S = Plus(dp[i][j].S, dp[i][j].F);
// cout << i << ' ' << j << ' ' << dp[i][j].F << ' ' << dp[i][j].S << '\n';
}
void solve (){
int N, M; cin >> N >> M;
dp.resize(N+17, vector <pll>(M+17, {0, 0}));
barrier.resize(N+17, vector <bool>(M+17, false));
gate.resize(N+17, vector <bool>(M+17, false));
for (int i = 1; i <= N; i++){
for (int j = 1; j <= M; j++){
char tmp; cin >> tmp;
if (tmp == 'x') barrier[i][j] = true;
else if (tmp == 'p') gate[i][j] = true;
}
}
dp[1][1].F = 1;
for (int i = 1; i <= N; i++){
for (int j = 1; j <= M; j++){
update(i, j);
}
}
cout << dp[N][M].F % MOD << '\n';
}
int main (){
icisc
solve();
}
存在一大小為 \(N × M\) 的棋盤
令左上為起點右下為終點
永遠都只能往右邊或下面走
另外棋盤上可能存在一些傳送門
可以利用傳送門,到達其右邊或下面
任何一個格子上
就算走到傳送門也可以選擇不進去
這樣算為兩種不同走法
求從起點到終點有多少種不同走法
步行過來:顯然直接上加左就好,無論他是用什麼鬼方法到那邊
的,No body cares
直接傳送:對於每個在其左邊與上面的傳送門,若有 \(K\) 種方法
可以到達該格,表示它也有 \(K\) 種路徑來直接傳送到目的地
prefix sum algorithm
AtCoder Beginner Contest Round 295 pD
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef long long int usll;
typedef pair <int, int> pii;
typedef priority_queue<int, vector <int>, less<int>> pqis;
typedef priority_queue<int, vector <int>, greater<int>> pqig;
typedef vector <vector <int>> vecii;
typedef set<int>::iterator setitr;
#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define F first
#define S second
#define pb push_back
void solve (){
string str; cin >> str;
vector <int> num;
for (int i = 0; i < str.size(); i++) num.pb(int(str[i] - '0'));
int record = 0;
usll ans = 0;
vector <int> exist(1e5 + 17, 0);
exist[0]++;
for (auto to:num){
int tmp = (1<<to);
record ^= tmp;
ans += exist[record];
exist[record]++;
}
cout << ans << '\n';
}
int main (){
icisc
solve();
}
給定一個由數字組成的字串
大小可達 \(5 × 10^5\)
如果一個字串中的數字經過重組後
能夠像 20230322 -> 20232023
這樣形成兩個,完全相同的數字
那我們就稱此數字是 快樂的
求整個字串中,你可以自由分割
惟在切割前不得變更順序
最多可形成多少個快樂的數字?
Knapsack
AtCoder Beginner Contest Round 317 pD
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef long long int usll;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef priority_queue<int, vector <int>, less<int>> pqis;
typedef priority_queue<int, vector <int>, greater<int>> pqig;
typedef vector <vector <int>> vecii;
typedef set<int>::iterator setitr;
#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define F first
#define S second
#define pb push_back
vector <pll> vec; // seats, need
vector <ll> dp; // dp[i] = how many extra voter required to reach exactally i seats
ll INF = 1e17;
void solve (){
ll N; cin >> N;
vec.resize(N+17, {0, 0});
ll seat_sum = 0;
for (ll i = 1; i <= N; i++){
ll a, b, c; cin >> a >> b >> c;
ll need = max(1ll*0, (a+b)/2 + 1 - a);
vec[i] = {c, need};
seat_sum += c;
}
dp.resize(seat_sum + 17, INF);
dp[0] = 0;
for (ll i = 1; i <= N; i++){
for (ll j = seat_sum; j >= vec[i].F; j--){
// printf("i = %I64d, j = %I64d, vec[i].F = %I64d, vec[i].S = %I64d\n", i , j, vec[i].F, vec[i].S);
dp[j] = min(dp[j], dp[j - vec[i].F] + vec[i].S);
// printf("dp[%I64d] = %I64d\n", j, dp[j]);
}
}
// cout << "Not crushed\n";
ll ans = INF;
for (ll i = seat_sum/2 + 1; i <= seat_sum; i++) ans = min(ans, dp[i]);
cout << ans << '\n';
}
int main (){
icisc
solve();
}
反正就是類似美國的選舉人團制度
這邊有 \(N\) 個選區
第 \(i\) 個選區有 \(Z\) 張選票
第 \(i\) 個選區中有 \(X\) 位投給 A 候選人
另外有 \(Y\) 位投給 B 候選人
在一個選區中
得票較高者可以拿走該選區的全部選票
最後獲得最多選票者將成為總統
求最少要有幾個原本投 B 的人轉投 A
才能讓 A 如願以償成為總統?
By repkironca