en

cyyyyyyyyyyyyy發表於2024-04-12

高精度加法
// C = A + B, A >= 0, B >= 0
vector<int> add(vector<int> &A, vector<int> &B)
{
if (A.size() < B.size()) return add(B, A);

vector<int> C;
int t = 0;
for (int i = 0; i < A.size(); i ++ )
{
t += A[i];
if (i < B.size()) t += B[i];
C.push_back(t % 10);
t /= 10;
}

if (t) C.push_back(t);
return C;
}


高精度減法
// C = A - B, 滿足A >= B, A >= 0, B >= 0
vector<int> sub(vector<int> &A, vector<int> &B)
{
vector<int> C;
for (int i = 0, t = 0; i < A.size(); i ++ )
{
t = A[i] - t;
if (i < B.size()) t -= B[i];
C.push_back((t + 10) % 10);
if (t < 0) t = 1;
else t = 0;
}

while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
高精度乘低精度
// C = A * b, A >= 0, b >= 0
vector<int> mul(vector<int> &A, int b)
{
vector<int> C;

int t = 0;
for (int i = 0; i < A.size() || t; i ++ )
{
if (i < A.size()) t += A[i] * b;
C.push_back(t % 10);
t /= 10;
}

while (C.size() > 1 && C.back() == 0) C.pop_back();

return C;
}
高精度除以低精度
// A / b = C ... r, A >= 0, b > 0
vector<int> div(vector<int> &A, int b, int &r)
{
vector<int> C;
r = 0;
for (int i = A.size() - 1; i >= 0; i -- )
{
r = r * 10 + A[i];
C.push_back(r / b);
r %= b;
}
reverse(C.begin(), C.end());
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}


一維字首和 —— 模板題 AcWing 795. 字首和
S[i] = a[1] + a[2] + ... a[i]
a[l] + ... + a[r] = S[r] - S[l - 1]
二維字首和 —— 模板題 AcWing 796. 子矩陣的和
S[i, j] = 第i行j列格子左上部分所有元素的和
以(x1, y1)為左上角,(x2, y2)為右下角的子矩陣的和為:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]
一維差分 —— 模板題 AcWing 797. 差分
給區間[l, r]中的每個數加上c:B[l] += c, B[r + 1] -= c
二維差分 —— 模板題 AcWing 798. 差分矩陣
給以(x1, y1)為左上角,(x2, y2)為右下角的子矩陣中的所有元素加上c:
S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c


STL
vector, 變長陣列,倍增的思想
size() 返回元素個數
empty() 返回是否為空
clear() 清空
front()/back()
push_back()/pop_back()
begin()/end()
[]
支援比較運算,按字典序

pair<int, int>
first, 第一個元素
second, 第二個元素
支援比較運算,以first為第一關鍵字,以second為第二關鍵字(字典序)

string,字串
size()/length() 返回字串長度
empty()
clear()
substr(起始下標,(子串長度)) 返回子串
c_str() 返回字串所在字元陣列的起始地址

queue, 佇列
size()
empty()
push() 向隊尾插入一個元素
front() 返回隊頭元素
back() 返回隊尾元素
pop() 彈出隊頭元素

priority_queue, 優先佇列,預設是大根堆
size()
empty()
push() 插入一個元素
top() 返回堆頂元素
pop() 彈出堆頂元素
定義成小根堆的方式:priority_queue<int, vector<int>, greater<int>> q;

stack, 棧
size()
empty()
push() 向棧頂插入一個元素
top() 返回棧頂元素
pop() 彈出棧頂元素

deque, 雙端佇列
size()
empty()
clear()
front()/back()
push_back()/pop_back()
push_front()/pop_front()
begin()/end()
[]

set, map, multiset, multimap, 基於平衡二叉樹(紅黑樹),動態維護有序序列
size()
empty()
clear()
begin()/end()
++, -- 返回前驅和後繼,時間複雜度 O(logn)

set/multiset
insert() 插入一個數
find() 查詢一個數
count() 返回某一個數的個數
erase()
(1) 輸入是一個數x,刪除所有x O(k + logn)
(2) 輸入一個迭代器,刪除這個迭代器
lower_bound()/upper_bound()
lower_bound(x) 返回大於等於x的最小的數的迭代器
upper_bound(x) 返回大於x的最小的數的迭代器
map/multimap
insert() 插入的數是一個pair
erase() 輸入的引數是pair或者迭代器
find()
[] 注意multimap不支援此操作。 時間複雜度是 O(logn)
lower_bound()/upper_bound()

unordered_set, unordered_map, unordered_multiset, unordered_multimap, 雜湊表
和上面類似,增刪改查的時間複雜度是 O(1)
不支援 lower_bound()/upper_bound(), 迭代器的++,--


線性篩法求素數
int primes[N], cnt; // primes[]儲存所有素數
bool st[N]; // st[x]儲存x是否被篩掉

void get_primes(int n)
{
for (int i = 2; i <= n; i ++ )
{
if (!st[i]) primes[cnt ++ ] = i;
for (int j = 0; primes[j] <= n / i; j ++ )
{
st[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}
}


快速冪
求 m^k mod p,時間複雜度 O(logk)。

int qmi(int m, int k, int p)
{
int res = 1 % p, t = m;
while (k)
{
if (k&1) res = res * t % p;
t = t * t % p;
k >>= 1;
}
return res;
}

擴充套件歐幾里得演算法
// 求x, y,使得ax + by = gcd(a, b)
int exgcd(int a, int b, int &x, int &y)
{
if (!b)
{
x = 1; y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= (a/b) * x;
return d;
}


揹包

01 每個物品只能選0次/1次
#include<bits/stdc++.h>

using namespace std;

const int MAXN = 1005;
int v[MAXN]; // 體積
int w[MAXN]; // 價值
int f[MAXN]; // f[i][j], j體積下前i個物品的最大價值

int main()
{
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i++)
cin >> v[i] >> w[i];

for(int i = 1; i <= n; i++)
for(int j = m; j >=v[i]; j--)
{
f[j] = max(f[j], f[j - v[i]] + w[i]);
}

cout << f[m] << endl;

return 0;
}

完全 每個物品無限

#include<bits/stdc++.h>

using namespace std;

const int MAXN = 1005;
int v[MAXN]; // 體積
int w[MAXN]; // 價值
int f[MAXN]; // f[i][j], j體積下前i個物品的最大價值

int main()
{
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i++)
cin >> v[i] >> w[i];

for(int i = 1; i <= n; i++)
for(int j = v[i]; j <=m; j++)
{
f[j] = max(f[j], f[j - v[i]] + w[i]);
}

cout << f[m] << endl;

return 0;
}

多重揹包 第i個物品最多si次

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 25000;

int f[N], v[N], w[N];
int n, m;

int main(){
cin >> n >> m;

//將每種物品根據物件個數進行打包
int cnt = 0;
for(int i = 1; i <= n; i ++){
int a, b, s;
cin >> a >> b >> s;

int k = 1;
while(k <= s){
cnt ++;
v[cnt] = k * a;
w[cnt] = k * b;
s -= k;
k *= 2;
}
if(s > 0){
cnt ++;
v[cnt] = s * a;
w[cnt] = s * b;
}

}

//多重揹包轉化為01揹包問題
for(int i = 1; i <= cnt; i ++){
for(int j = m; j >= v[i]; j --){
f[j] = max(f[j], f[j - v[i]] + w[i]);
}
}

cout << f[m] << endl;

return 0;
}