一、数论
1.试除法判定质数
cpp
#include<iostream>
using namespace std;
int ff(int x){
if(x < 2) return 0;
for(int i = 2; i <= x / i; i++){
if(x % i == 0) return 0;
}
return 1;
}
int main(){
int t;
cin>>t;
int x;
while(t--){
cin>>x;
int y = ff(x);
if(y) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}
2.分解质因数
cpp
#include<iostream>
using namespace std;
void ff(int x){
for(int i = 2; i <= x / i; i++){
if(x % i == 0){
int cnt = 0;
while(x % i == 0){
cnt++;
x /= i;
}
cout<<i<<" "<<cnt<<endl;
}
}
if(x > 1) cout<<x<<" "<<1<<endl;
}
int main(){
int n;
cin>>n;
int x;
while(n--){
cin>>x;
ff(x);
cout<<endl;
}
return 0;
}
3.筛质数
cpp
// 埃氏筛法
#include<iostream>
using namespace std;
const int N = 1e6;
int prim[N], vis[N];
void ff(int n){
int cnt = 0;
for(int i = 2; i <= n; i++){
if(!vis[i]){
vis[i] = 1;
prim[++cnt] = i;
for(int j = i + i; j <= n; j += i) vis[j] = 1;
}
}
for(int i = 1; i <= cnt; i++) cout<<prim[i]<<" ";
cout<<endl;
cout<<cnt;
}
int main(){
int n;
cin>>n;
ff(n);
return 0;
}
// 线性筛法
#include<iostream>
using namespace std;
const int N = 1e6;
int prim[N], vis[N];
void ff(int n){
int cnt = 0;
for(int i = 2; i <= n; i++){
if(!vis[i]){
vis[i] = 1;
prim[++cnt] = i;
}
for(int j = 1; prim[j] <= n / i; j++){
// 用最小质因子筛合数
vis[i * prim[j]] = 1;
if(i % prim[j] == 0) break;
}
}
//for(int i = 1; i <= cnt; i++) cout<<prim[i]<<" ";
//cout<<endl;
cout<<cnt;
}
int main(){
int n;
cin>>n;
ff(n);
return 0;
}
4.试除法求约数
cpp
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
void ff(int x){
int cnt = 0;
vector<int> v;
for(int i = 1; i <= x / i; i++){
if(x % i == 0){
v.push_back(i);
if(x / i != i) v.push_back(x / i);
}
}
sort(v.begin(), v.end());
for(int i : v) cout<<i<<" ";
}
int main(){
int n;
cin>>n;
int x;
while(n--){
cin>>x;
ff(x);
cout<<endl;
}
return 0;
}
5.约数个数
cpp
#include<iostream>
#include<map>
using namespace std;
const int mod = 1e9 + 7;
map<int, int> mp;
void ff(int x){
for(int i = 2; i <= x / i; i++){
while(x % i == 0){
mp[i]++;
x /= i;
}
}
if(x > 1) mp[x]++;
}
int main(){
int n;
cin>>n;
int x;
while(n--){
cin>>x;
ff(x);
}
long long ans = 1;
for(auto i : mp){
ans = ans * (i.second + 1) % mod;
}
cout<<ans;
return 0;
}
6.约数之和
cpp
#include<iostream>
#include<map>
using namespace std;
const int mod = 1e9 + 7;
map<int, int> mp;
void ff(int x){
for(int i = 2; i <= x / i; i++){
while(x % i == 0){
mp[i]++;
x /= i;
}
}
if(x > 1) mp[x]++;
}
int main(){
int n;
cin>>n;
int x;
while(n--){
cin>>x;
ff(x);
}
long long ans = 1;
for(auto i : mp){
long long res = 1;
int a = i.first, b = i.second;
while(b--){
res = (res * a + 1) % mod;
}
ans = (ans * res) % mod;
}
cout<<ans;
return 0;
}
7.最大公约数
cpp
#include<iostream>
using namespace std;
int gcd(int a, int b){
if(b == 0) return a;
else return gcd(b, a % b);
}
int main(){
int n;
cin>>n;
int a, b;
while(n--){
cin>>a>>b;
int res = gcd(a, b);
cout<<res<<endl;
}
return 0;
}
8.最小公倍数
cpp
#include<iostream>
using namespace std;
int gcd(int a, int b){
if(b == 0) return a;
else return gcd(b, a % b);
}
int main(){
int n;
cin>>n;
int a, b;
while(n--){
cin>>a>>b;
int res = a * b / gcd(a, b);
cout<<res<<endl;
}
return 0;
}
9.欧拉函数
cpp
#include<iostream>
using namespace std;
void ff(int x){
int res = x;
for(int i = 2; i <= x / i; i++){
if(x % i == 0){
while(x % i == 0){
x /= i;
}
res = res / i * (i - 1);
}
}
if(x > 1) res = res / x * (x - 1);
cout<<res<<endl;
}
int main(){
int n;
cin>>n;
int x;
while(n--){
cin>>x;
ff(x);
}
return 0;
}
10.快速幂
cpp
#include<iostream>
using namespace std;
void ff(int a, int b, int p){
int res = 1 % p;
while(b){
if(b & 1) res = 1ll * res * a % p;
a = 1ll * a * a % p;
b >>= 1;
}
cout<<res<<endl;
}
int main(){
int n;
cin>>n;
int a, b, p;
while(n--){
cin>>a>>b>>p;
ff(a, b, p);
}
return 0;
}
11.快速幂求逆元
a / b ≡ a * x (mod n)
两边同乘b可得 a ≡ a * b * x (mod n)
即 1 ≡ b * x (mod n)
同 b * x ≡ 1 (mod n)
由费马小定理可知,当n为质数时
b ^ (n - 1) ≡ 1 (mod n)
拆一个b出来可得 b * b ^ (n - 2) ≡ 1 (mod n)
故当n为质数时,b的乘法逆元 x = b ^ (n - 2)
cpp
#include<iostream>
using namespace std;
int ff(int a, int b, int p){
int res = 1 % p;
while(b){
if(b & 1) res = 1ll * res * a % p;
a = 1ll * a * a % p;
b >>= 1;
}
return res;
}
int main(){
int n;
cin>>n;
int a, p;
while(n--){
cin>>a>>p;
int res = ff(a, p - 2, p);
if(a % p) cout<<res<<endl;
else cout<<"impossible"<<endl;
}
return 0;
}
12.扩展欧几里得
裴蜀定理:有一对正整数 a,b,那么一定存在非零 x,y,使得 ax + by = gcd(a, b)
即 a 和 b 的最大公因数是 a 和 b 能凑出来的最小正整数
cpp
#include<iostream>
using namespace std;
int exgcd(int a, int b, int &x, int &y){
if(b == 0){
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
int main(){
int n;
cin>>n;
int a, b;
while(n--){
cin>>a>>b;
int x, y;
int res = exgcd(a, b, x, y);
//cout<<res<<endl;
cout<<x<<" "<<y<<endl;
}
return 0;
}
13.扩展欧几里得求逆元
a有逆元的充要条件是a与p互质,所以gcd(a, p) = 1
假设a的逆元为x,那么有a * x ≡ 1 (mod p)
等价:ax + py = 1
exgcd(a, p, x, y)
cpp
#include<iostream>
using namespace std;
int exgcd(int a, int b, int &x, int &y){
if(b == 0){
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
int main(){
int n;
cin>>n;
int a, p;
while(n--){
cin>>a>>p;
int x, y;
int d = exgcd(a, p, x, y);
if(d == 1) cout<<(1ll * x + p) % p<<endl;
else cout<<"impossible"<<endl;
}
return 0;
}
14.求组合数
cpp
// 在 2000 范围内
#include<iostream>
using namespace std;
const int N = 2e3 + 10, mod = 1e9 + 7;
int f[N][N];
void init(){
f[0][0] = f[1][0] = f[1][1] = 1;
for(int i = 2; i < N; i++){
for(int j = 0; j <= i; j++){
if(!j) f[i][j] = 1;
else f[i][j] = (f[i - 1][j] + f[i - 1][j - 1]) % mod;
}
}
}
int main(){
init();
int n;
cin>>n;
int a, b;
while(n--){
cin>>a>>b;
cout<<f[a][b]<<endl;
}
return 0;
}
// 在 100000 范围内
#include<iostream>
using namespace std;
const int N = 1e5 + 10, mod = 1e9 + 7;
int fact[N], infact[N];
int qm(int a, int b, int p){
int res = 1 % p;
while(b){
if(b & 1) res = 1ll * res * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return res;
}
void init(){
fact[0] = infact[0] = 1;
for(int i = 1; i < N; i++){
fact[i] = 1ll * fact[i - 1] * i % mod;
infact[i] = 1ll* infact[i - 1] * qm(i, mod - 2, mod) % mod;
}
}
int main(){
init();
int n;
cin>>n;
int a, b;
while(n--){
cin>>a>>b;
int res = 1ll * fact[a] * infact[a - b] % mod * infact[b] % mod;
cout<<res<<endl;
}
return 0;
}
二、图论
1.拓扑序列
cpp
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int N = 1e5 + 10;
vector<int> g[N];
int ru[N], a[N];
int n, m;
void ff(){
queue<int> q;
for(int i = 1; i <= n; i++){
if(!ru[i]){
q.push(i);
}
}
int siz = 0;
while(q.size()){
int x = q.front();
q.pop();
a[++siz] = x;
for(int y : g[x]){
if(ru[y]){
ru[y]--;
if(!ru[y]){
q.push(y);
}
}
}
}
if(siz != n) cout<<-1;
else{
for(int i = 1; i <= siz; i++){
cout<<a[i]<<" ";
}
}
}
int main(){
cin>>n>>m;
int x, y;
for(int i = 1; i <= m; i++){
cin>>x>>y;
g[x].push_back(y);
ru[y]++;
}
ff();
return 0;
}
2.dijkstra
cpp
// O(n ^ 2)
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 510;
vector<pair<int, int>> g[N];
int vis[N], dis[N];
int n, m;
void ff(int st, int ed){
memset(dis, 0x7f, sizeof(dis));
dis[st] = 0;
while(1){
int x = -1;
for(int i = 1; i <= n; i++){
if(!vis[i] && dis[i] < 0x3f3f3f3f && (x == -1 || dis[x] > dis[i])){
x = i;
}
}
if(x == -1 || x == ed) break;
vis[x] = 1;
for(auto i : g[x]){
int y = i.first, z = i.second;
if(dis[x] + z < dis[y]){
dis[y] = dis[x] + z;
}
}
}
if(dis[ed] < 0x3f3f3f3f) cout<<dis[ed];
else cout<<-1;
}
int main(){
cin>>n>>m;
int x, y, z;
for(int i = 1; i <= m; i++){
cin>>x>>y>>z;
// 判重,取边权小的
int ok = 0;
for(auto& j : g[x]){
if(j.first == y){
if(j.second > z){
j.second = z;
}
ok = 1;
break;
}
}
if(!ok) g[x].push_back({y, z});
}
ff(1, n);
return 0;
}
// O((n + m)logn)
```cpp
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
#include<set>
using namespace std;
const int N = 2e5 + 10;
vector<pair<int, int>> g[N];
set<pair<int, int>> q;
int dis[N];
int n, m;
void ff(int st, int ed){
memset(dis, 0x7f, sizeof(dis));
dis[st] = 0;
for(int i = 1; i <= n; i++){
q.insert({dis[i], i});
}
while(q.size()){
auto x = q.begin() -> second;
q.erase(q.begin());
if(x == ed || dis[x] > 0x3f3f3f3f) break;
for(auto i : g[x]){
int y = i.first, z = i.second;
if(dis[x] + z < dis[y]){
q.erase({dis[y], y});
dis[y] = dis[x] + z;
q.insert({dis[y], y});
}
}
}
if(dis[ed] < 0x3f3f3f3f) cout<<dis[ed];
else cout<<-1;
}
int main(){
cin>>n>>m;
int x, y, z;
for(int i = 1; i <= m; i++){
cin>>x>>y>>z;
int ok = 0;
// for(auto& j : g[x]){
// if(j.first == y){
// if(j.second > z){
// j.second = z;
// }
// ok = 1;
// break;
// }
// }
if(!ok) g[x].push_back({y, z});
}
ff(1, n);
return 0;
}
3.bellman
cpp
#include<iostream>
#include<cstring>
using namespace std;
const int N = 1e4 + 10;
struct Point{
int x, y, z;
}g[N];
int dis[N], b[N], pre[N];
int n, m, k;
void ff(int st, int ed){
memset(dis, 0x7f, sizeof(dis));
dis[st] = 0;
int cnt = 0;
while(1){
cnt++;
int ok = 0;
// 每次只能用之前的状态更新
memcpy(b, dis, sizeof(dis));
for(int i = 1; i <= m; i++){
int x = g[i].x, y = g[i].y, z = g[i].z;
if(dis[x] < 0x3f3f3f3f && b[x] + z < dis[y]){
dis[y] = b[x] + z;
pre[y] = x;
ok = 1;
}
}
if(!ok || cnt >= k) break;
}
if(dis[ed] < 0x3f3f3f3f){
// for(int i = ed; i != st; i = pre[i]){
// cout<<i<<" ";
// }
// cout<<st<<endl;
cout<<dis[ed];
}
else cout<<"impossible";
}
int main(){
cin>>n>>m>>k;
int x, y, z;
for(int i = 1; i <= m; i++){
cin>>x>>y>>z;
g[i] = {x, y, z};
}
ff(1, n);
return 0;
}
4.spfa
cpp
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
const int N = 1e5 + 10;
vector<pair<int, int>> g[N];
queue<int> q;
int dis[N], vis[N], pre[N];
int n, m;
void ff(int st, int ed){
memset(dis, 0x7f, sizeof(dis));
dis[st] = 0;
vis[st] = 1;
q.push(st);
while(q.size()){
int x = q.front();
q.pop();
vis[x] = 0;
for(auto i : g[x]){
int y = i.first, z = i.second;
if(dis[x] < 0x3f3f3f3f && dis[x] + z < dis[y]){
dis[y] = dis[x] + z;
pre[y] = x;
if(!vis[y]){
q.push(y);
vis[y] = 1;
}
}
}
}
if(dis[ed] < 0x3f3f3f3f) cout<<dis[ed];
else cout<<"impossible";
}
int main(){
cin>>n>>m;
int x, y, z;
for(int i = 1; i <= m; i++){
cin>>x>>y>>z;
g[x].push_back({y, z});
}
ff(1, n);
return 0;
}
// 判负环,如果最短路径边数大于等于 n,那就有负环
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
const int N = 1e5 + 10;
vector<pair<int, int>> g[N];
queue<int> q;
int dis[N], vis[N], pre[N], cnt[N];
int n, m;
void ff(){
//memset(dis, 0x7f, sizeof(dis));
for(int i = 1; i <= n; i++){
q.push(i);
vis[i] = 1;
}
int ok = 0;
while(q.size()){
int x = q.front();
q.pop();
vis[x] = 0;
for(auto i : g[x]){
int y = i.first, z = i.second;
if(dis[x] < 0x3f3f3f3f && dis[x] + z < dis[y]){
dis[y] = dis[x] + z;
cnt[y] = cnt[x] + 1;
if(cnt[y] >= n){
ok = 1;
break;
}
pre[y] = x;
if(!vis[y]){
q.push(y);
vis[y] = 1;
}
}
}
if(ok) break;
}
if(ok) cout<<"Yes";
else cout<<"No";
}
int main(){
cin>>n>>m;
int x, y, z;
for(int i = 1; i <= m; i++){
cin>>x>>y>>z;
g[x].push_back({y, z});
}
ff();
return 0;
}
5.floyd
cpp
#include<iostream>
#include<cstring>
using namespace std;
const int N = 210;
int f[N][N], dis[N][N];
int n, m, q;
int main(){
cin>>n>>m>>q;
int x, y, z;
memset(dis, 0x7f, sizeof(dis));
for(int i = 1; i <= m; i++){
cin>>x>>y>>z;
dis[x][y] = min(dis[x][y], z);
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(i == j) f[i][j] = 0;
else f[i][j] = dis[i][j];
}
}
for(int k = 1; k <= n; k++){
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(f[i][k] < 0x3f3f3f3f && f[k][j] < 0x3f3f3f3f){
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
}
}
}
}
while(q--){
cin>>x>>y;
if(f[x][y] < 0x3f3f3f3f) cout<<f[x][y]<<endl;
else cout<<"impossible"<<endl;
}
return 0;
}
6.prim
cpp
// O(n ^ 2)
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 550;
vector<pair<int, int>> g[N];
int vis[N], dis[N];
int n, m;
int test(int st){
memset(dis, 0x7f, sizeof(dis));
dis[st] = 0;
int ans = 0, cnt = 0;
while(1){
int x = -1;
for(int i = 1; i <= n; i++){
if(!vis[i] && dis[i] < 0x3f3f3f3f && (x == -1 || dis[i] < dis[x])){
x = i;
}
}
if(x == -1) break;
vis[x] = 1;
cnt++;
ans += dis[x];
for(auto i : g[x]){
int y = i.first, w = i.second;
dis[y] = min(dis[y], w);
}
}
if(cnt != n) return 1e9;
else return ans;
}
int main(){
scanf("%d%d", &n, &m);
int x, y, w;
for(int i = 1; i <= m; i++){
scanf("%d%d%d", &x, &y, &w);
g[x].push_back({y, w});
g[y].push_back({x, w});
}
int res = test(1);
if(res != 1e9) printf("%d", res);
else printf("impossible");
return 0;
}
// O((n + m)logn)
#include<iostream>
#include<set>
#include<vector>
#include<cstring>
using namespace std;
const int N = 550;
set<pair<int, int>> q;
vector<pair<int, int>> g[N];
int dis[N], vis[N];
int n, m;
int test(int st){
memset(dis, 0x7f, sizeof(dis));
dis[st] = 0;
for(int i = 1; i <= n; i++){
q.insert({dis[i], i});
}
int ans = 0, cnt = 0;
while(q.size()){
int x = q.begin() -> second;
q.erase(q.begin());
vis[x] = 1;
if(dis[x] > 0x3f3f3f3f) break;
ans += dis[x];
cnt++;
for(auto i : g[x]){
int y = i.first, w = i.second;
if(!vis[y] && w < dis[y]){
q.erase({dis[y], y});
dis[y] = w;
q.insert({dis[y], y});
}
}
}
if(cnt != n) return 1e9;
else return ans;
}
int main(){
scanf("%d%d", &n, &m);
int x, y, w;
for(int i = 1; i <= m; i++){
scanf("%d%d%d", &x, &y, &w);
g[x].push_back({y, w});
g[y].push_back({x, w});
}
int res = test(1);
if(res == 1e9) printf("impossible");
else printf("%d", res);
return 0;
}
7.kruskal
cpp
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 2e5 + 10;
struct Point{
int x, y, z;
bool operator<(const Point& p)const{
return z < p.z;
}
}g[N];
int p[N];
int n, m;
int cnt;
int fd(int x){
if(x != p[x]){
p[x] = fd(p[x]);
}
return p[x];
}
void ff(){
for(int i = 1; i <= n; i++){
p[i] = i;
}
sort(g + 1, g + cnt + 1);
int ans = 0, res = 0;
for(int i = 1; i <= cnt; i++){
int x = g[i].x, y = g[i].y, z = g[i].z;
int xx = fd(x), yy = fd(y);
if(xx != yy){
p[yy] = xx;
ans += z;
res++;
}
//if(res == n - 1) break;
}
if(res < n - 1) cout<<"impossible";
else cout<<ans;
}
int main(){
cin>>n>>m;
int x, y, z;
for(int i = 1; i <= m; i++){
cin>>x>>y>>z;
g[++cnt] = {x, y, z};
//g[++cnt] = {y, x, z};
}
ff();
return 0;
}
三、贪心
1.区间选点
cpp
#include<bits/stdc++.h>
using namespace std;
vector<pair<int, int>> a;
int n, cnt;
bool cmp(const pair<int, int> &p, const pair<int, int> &q){
return p.second < q.second;
}
int main(){
cin>>n;
while(n--){
int l, r;
cin>>l>>r;
a.push_back({l, r});
}
sort(a.begin(), a.end(), cmp);
int ed = -2e9;
for(auto it : a){
if(ed < it.first){
cnt++;
ed = it.second;
}
}
cout<<cnt;
return 0;
}
2.最大不相交区间数量
cpp
#include<bits/stdc++.h>
using namespace std;
vector<pair<int, int>> a;
int n, cnt;
bool cmp(const pair<int, int> &p, const pair<int, int> &q){
return p.second < q.second;
}
int main(){
cin>>n;
while(n--){
int l, r;
cin>>l>>r;
a.push_back({l, r});
}
sort(a.begin(), a.end(), cmp);
int ed = -2e9;
for(auto it : a){
if(ed < it.first){
cnt++;
ed = it.second;
}
}
cout<<cnt;
return 0;
}
3.区间分组
cpp
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
vector<pair<int, int>> a;
int n;
bool cmp(const pair<int, int> &x, const pair<int, int> &y){
return x.first < y.first;
}
int main(){
cin>>n;
for(int i = 0; i < n; i++){
int l, r;
cin>>l>>r;
a.push_back({l, r});
}
sort(a.begin(), a.end(), cmp);
priority_queue<int, vector<int>, greater<int>> h;
int m = a.size();
for(int i = 0; i < m; i++){
if(h.empty() || h.top() >= a[i].first) h.push(a[i].second);
else{
h.pop();
h.push(a[i].second);
}
}
cout<<h.size(); //h.size()是size_t类型,无符号整数
return 0;
}
4.区间覆盖
cpp
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int st, ed;
int res;
int n;
int f;
vector<pair<int, int>> a;
int main(){
cin>>st>>ed;
cin>>n;
for(int i = 0; i < n; i++){
int l, r;
cin>>l>>r;
a.push_back({l, r});
}
sort(a.begin(), a.end());
for(int i = 0; i < n; i++){
int j = i, r = -2e9;
while(j < n && a[j].first <= st){
r = max(r, a[j].second);
j++;
}
if(r < st) break;
res++;
if(r >= ed){
f = 1;
break;
}
st = r;
i = j - 1;
}
if(f == 1) cout<<res;
else cout<<-1;
return 0;
}
四、数据结构
1.kmp
cpp
#include<iostream>
using namespace std;
const int N = 1e6 + 10;
char s[N], p[N];
int ne[N], f[N];
int n, m;
void ff(){
ne[1] = 0;
int j = 0;
for(int i = 2; i <= m; i++){
while(j > 0 && p[i] != p[j + 1]) j = ne[j];
if(p[i] == p[j + 1]) j++;
ne[i] = j;
}
j = 0;
for(int i = 1; i <= n; i++){
while(j > 0 && s[i] != p[j + 1]) j = ne[j];
if(s[i] == p[j + 1]) j++;
f[i] = j;
}
for(int i = 1; i <= n; i++){
if(f[i] == m){
cout<<(i - m)<<" ";
}
}
}
int main(){
cin>>m;
cin>>(p + 1);
cin>>n;
cin>>(s + 1);
ff();
return 0;
}
2.z函数
cpp
#include<iostream>
using namespace std;
const int N = 2e6 + 10;
char s[N], p[N];
int z[N];
int n, m;
void ff(){
p[m + 1] = '#';
for(int i = m + 2, j = 1; j <= n; i++, j++){
p[i] = s[j];
}
z[1] = 0;
int L = 1, R = 0;
for(int i = 2; i <= n + m + 1; i++){
if(i > R){
z[i] = 0;
}else{
int k = i - L + 1;
z[i] = min(z[k], R - i + 1);
}
while(z[i] + i <= n + m + 1 && p[z[i] + 1] == p[z[i] + i]){
z[i]++;
}
if(z[i] + i - 1 > R){
L = i, R = z[i] + i - 1;
}
}
for(int i = m + 2; i <= n + m + 1; i++){
if(z[i] == m){
cout<<(i - m - 2)<<" ";
}
}
}
int main(){
cin>>m;
cin>>(p + 1);
cin>>n;
cin>>(s + 1);
ff();
return 0;
}
3.trie树
cpp
// 字符统计
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int son[N][26], cnt[N], idx;
int n;
void insert(string s){
// 0是根节点
int p = 0;
for(int i = 0; i < s.size(); i++){
int u = s[i] - 'a';
if(!son[p][u]) son[p][u] = ++idx;
p = son[p][u];
}
cnt[p]++;
}
int query(string s){
int p = 0;
for(int i = 0; i < s.size(); i++){
int u = s[i] - 'a';
if(!son[p][u]) return 0;
p = son[p][u];
}
return cnt[p];
}
int main(){
cin>>n;
char c;
string s;
while(n--){
cin>>c;
if(c == 'I'){
cin>>s;
insert(s);
}else{
cin>>s;
cout<<query(s)<<endl;
}
}
return 0;
}
// 求数组两个数最大异或
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int son[31 * N][2], idx;
int n;
void insert(int x){
int p = 0;
for(int i = 30; i >= 0; i--){
int u = x >> i & 1;
if(!son[p][u]) son[p][u] = ++idx;
p = son[p][u];
}
}
int query(int x){
int p = 0, sum = 0;
for(int i = 30; i >= 0; i--){
int u = x >> i & 1;
if(son[p][!u]){
p = son[p][!u];
sum = 2 * sum + 1;
}else{
p = son[p][u];
sum = 2 * sum + 0;
}
}
return sum;
}
int main(){
cin>>n;
int x, res;
while(n--){
cin>>x;
insert(x);
res = max(res, query(x));
}
cout<<res;
return 0;
}
4.并查集
cpp
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int p[N];
int n, m;
int find(int x){
if(x != p[x]) p[x] = find(p[x]);
return p[x];
}
int main(){
cin>>n>>m;
for(int i = 1; i <= n; i++) p[i] = i;
char c;
int a, b;
while(m--){
cin>>c;
cin>>a>>b;
if(c == 'M'){
if(find(a) == find(b)) continue;
p[find(a)] = find(b);
}else{
cout<<(find(a) == find(b) ? "Yes" : "No")<<endl;
}
}
return 0;
}
五、基础算法
快速排序
cpp
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N], n;
void q(int a[], int l, int r){
if(l >= r) return;
int mid = a[(l + r + 1) / 2], i = l - 1, j = r + 1;
while(i < j){
do i++; while(a[i] < mid);
do j--; while(a[j] > mid);
if(i < j) swap(a[i], a[j]);
}
q(a, l, i - 1);
q(a, i, r);
}
int main(){
cin>>n;
for(int i = 1; i <= n; i++) cin>>a[i];
q(a, 1, n);
for(int i = 1; i <= n; i++) cout<<a[i]<<" ";
return 0;
}
归并排序
cpp
#include<iostream>
using namespace std;
const int N = 1e6 + 10;
int a[N], b[N], n;
void q(int a[], int l, int r){
if(l >= r) return;
int mid = (l + r) / 2;
q(a, l, mid), q(a, mid + 1, r);
int x = 1, i = l, j = mid + 1;
while(i <= mid && j <= r){
if(a[i] <= a[j]) b[x++] = a[i++];
else b[x++] = a[j++];
}
while(i <= mid) b[x++] = a[i++];
while(j <= r) b[x++] = a[j++];
for(int i = l, j = 1; i <= r; i++, j++) a[i] = b[j];
}
int main(){
cin>>n;
for(int i = 1; i <= n; i++) cin>>a[i];
q(a, 1, n);
for(int i = 1; i <= n; i++) cout<<a[i]<<" ";
return 0;
}
六、动态规划
1.01背包
cpp
#include<iostream>
using namespace std;
const int N = 1e3 + 10;
int f[N];
int n, m;
int v, w;
int main(){
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++){
scanf("%d%d", &v, &w);
for(int j = m; j >= v; j--){
f[j] = max(f[j], f[j - v] + w);
}
}
printf("%d", f[m]);
return 0;
}
2.完全背包
cpp
#include<iostream>
using namespace std;
const int N = 1e3 + 10;
int f[N];
int n, m;
int main(){
scanf("%d%d", &n, &m);
int v, w;
for(int i = 0; i < n; i++){
scanf("%d%d", &v,&w);
for(int j = v; j <= m; j++){
f[j] = max(f[j], f[j - v] + w);
}
}
printf("%d", f[m]);
return 0;
}
3.多重背包
cpp
#include<iostream>
#include<vector>
using namespace std;
const int N = 1e4 + 10;
int f[N];
int n, m;
struct Point{
int v, w;
};
int main(){
int hh1, mm1, hh2, mm2;
scanf("%d:%d %d:%d %d", &hh1, &mm1, &hh2, &mm2, &n);
m = hh2 * 60 + mm2 - (hh1 * 60 + mm1);
int v, w, s;
vector<Point> a;
for(int i = 1; i <= n; i++){
cin>>v>>w>>s;
if(s == 0){
s = 1000;
}
for(int j = 1; j <= s; j *= 2){
a.push_back({j * v, j * w});
s -= j;
}
if(s > 0){
a.push_back({s * v, s * w});
}
}
for(int i = 0; i < a.size(); i++){
for(int j = m; j >= a[i].v; j--){
f[j] = max(f[j], f[j - a[i].v] + a[i].w);
}
}
cout<<f[m];
return 0;
}
4.混合背包
cpp
#include<iostream>
#include<vector>
using namespace std;
const int N = 1010;
int f[N];
int n, m;
struct Good{
int id;
int v, w;
};
int main(){
scanf("%d%d", &n, &m);
vector<Good> goods;
int v, w, s;
for(int i = 0; i < n; i++){
scanf("%d%d%d", &v, &w, &s);
if(s == -1) goods.push_back({-1, v, w});
else if(s == 0) goods.push_back({0, v, w});
else{
for(int j = 1; j <= s; j *= 2){
s -= j;
goods.push_back({-1, j * v, j * w});
}
if(s > 0) goods.push_back({-1, s * v, s * w});
}
}
for(auto good : goods){
if(good.id == -1){
for(int j = m; j >= good.v; j--){
f[j] = max(f[j], f[j - good.v] + good.w);
}
}else{
for(int j = good.v; j <= m; j++){
f[j] = max(f[j], f[j - good.v] + good.w);
}
}
}
printf("%d", f[m]);
return 0;
}
5.分组背包
cpp
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int f[N];
int v[N], w[N];
int b[N], g[110][110];
int n, m;
int main(){
cin>>m>>n;
int x, t = 0;
for(int i = 1; i <= n; i++){
cin>>v[i]>>w[i]>>x;
t = max(t, x);
// 小组 x 的物品个数加一
b[x]++;
// 小组 i 中第 j 个物品的编号
g[x][b[x]] = i;
}
for(int i = 1; i <= t; i++){
for(int j = m; j >= 0; j--){
for(int z = 1; z <= b[i]; z++){
if(j >= v[g[i][z]]){
f[j] = max(f[j], f[j - v[g[i][z]]] + w[g[i][z]]);
}
}
}
}
cout<<f[m];
return 0;
}
6.背包问题求具体方案数
cpp
#include<iostream>
using namespace std;
const int N = 1010, mod = 1e9 + 7;
int f[N], sum[N];
int n, m;
int v, w;
int main(){
scanf("%d%d", &n, &m);
for(int i = 0; i <= m; i++) sum[i] = 1;
for(int i = 0; i < n; i++){
scanf("%d%d", &v, &w);
for(int j = m; j >= v; j--){
int t = f[j - v] + w;
if(t > f[j]){
f[j] = t;
sum[j] = sum[j - v];
}
else if(t == f[j]) sum[j] = (sum[j] + sum[j - v]) % mod;
}
}
printf("%d", sum[m]);
return 0;
}
7.背包问题求具体方案
cpp
#include<iostream>
using namespace std;
const int N = 1010;
int f[N][N], v[N], w[N];
int sp[N];
int n, m;
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%d%d", &v[i], &w[i]);
for(int i = n; i >= 1; i--){
for(int j = 0; j <= m; j++){
f[i][j] = f[i + 1][j];
if(j >= v[i]){
f[i][j] = max(f[i][j], f[i + 1][j - v[i]] + w[i]);
}
}
}
int cnt = 0;
for(int i = 1, j = m; i <= n; i++){
if(j >= v[i] && f[i][j] == f[i + 1][j - v[i]] + w[i]){
sp[++cnt] = i;
j -= v[i];
}
}
for(int i = 1; i <= cnt; i++) printf("%d ", sp[i]);
return 0;
}