可以用來監督建電學術水了多久
有個叫蘇昱亘的人,為了考上嚮往已久的建電學術,在 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 如願以償成為總統?