图论
2-SAT加边
1. x and y = false
说明两者不能同时选
(x,true)->(y,false),(y,true)->(x,false)
2. x or y = true
说明两者不能同时不选
(x,false)->(y,true),(y,false)->(x,true)
3. x xor y = true
说明两者不能一样
(x,true)->(y,false),(y,true)->(x,false)
(x,false)->(y,true),(y,false)->(x,true)
4. x xor y = false
说明两者要一样
(x,true)->(y,true),(y,true)->(x,true)
(x,false)->(y,false),(y,false)->(x,false)
5. x and y = true
两者一定要为true
(x,false)->(x,true),(y,false)->(y,true)
6. x or y = false
两者一定为false
(x,true)->(x,false),(y,true)->(y,false)
单源最短路 Dijkstra算法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e5+10;
const int M = 5e5+10;
const int INF = 0x7fffffff;
int cnt;
int n, m, s;
int head[MAX], dis[MAX], vis[MAX];
struct Node {
int dis;
int pos;
bool operator < (const Node &x)const {
return x.dis < dis;
}
Node(int D, int P): dis(D), pos(P){}
};
struct edge {
int nxt, to, dis;
}a[M];
void ADD(int u, int v, int d)
{
cnt++;
a[cnt].to = v;
a[cnt].dis = d;
a[cnt].nxt = head[u];
head[u] = cnt;
}
void dijkstra()
{
dis[s] = 0;
priority_queue<Node> Q;
Q.push(Node(0, s));
while (!Q.empty()) {
Node qq = Q.top();
Q.pop();
int x = qq.pos; int D = qq.dis;
if(vis[x]) continue;
vis[x] = 1;
for (int i = head[x]; i; i = a[i].nxt) {
int y = a[i].to;
if (dis[y] > dis[x] + a[i].dis) {
dis[y] = dis[x] + a[i].dis;
p[y] = i;
Q.push(Node(dis[y], a[i].to));
}
}
}
}
int main()
{
cin >> n >> m >> s;
for (int i = 1; i <= n; i++) {dis[i] = INF;}
for (int i = 0; i < m; i++) {
int from, to, dis;
cin >> from >> to >> dis;
ADD(from, to, dis);
}
dijkstra();
for (int i = 1; i <= n; i++) cout << dis[i] << " ";
return 0;
}
次短路
如果求第k短路将dijkstra中的flag == 2该为flag == k
这个写法每个点只能到一次,多次见下方
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int MAX = 1e5+120;
struct Edge{int to, nxt;double d;}e[MAX];
int head[MAX], idx, x[MAX], y[MAX];
void add(int u, int v, double d) {e[++idx].to = v, e[idx].nxt = head[u], head[u] = idx, e[idx].d = d;}
db calc(int i, int j) {return sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i]- y[j]));}
struct Node {int u; db d, g; bool vis[205]; Node(){memset(vis, 0, sizeof (vis));} };
int inq[MAX];
db dis[MAX];
bool operator < (Node x, Node y) {return x.d + x.g > y.d + y.g;}
void spfa(int n)
{
fill(dis + 1, dis + 1 + n, 1000000000);
dis[n] = 0;
queue<int> Q;
Q.push(n);
while (!Q.empty()) {
int u = Q.front(); Q.pop();
inq[u] = 0;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;double d = e[i].d;
if (dis[v] > dis[u] + d) {
dis[v] = dis[u] + d;
if (!inq[v]) {
inq[v] = 1;Q.push(v);
}
}
}
}
}
db dijkstra(int n)
{
int flag = 0;
priority_queue<Node> Q;
Node st;st.g = dis[1], st.d = 0, st.u = 1;
Q.push(st);
while (!Q.empty()) {
Node q = Q.top(); Q.pop();
if (q.vis[q.u]) continue;
q.vis[q.u] = 1;
if (q.u == n) flag++;
if (flag == 2) return q.d;
int u = q.u;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
Node nxt = q; nxt.u = v, nxt.g = dis[v], nxt.d = q.d + e[i].d;
Q.push(nxt);
}
}
return -1;
}
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> x[i] >> y[i];
}
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
add(u, v, calc(u, v));add(v, u, calc(u, v));
}
spfa(n);
printf("%.2lf", dijkstra(n));
return 0;
}
K短路
有向边,所以需要建一个反向的图求终点距离。。。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5+120;
struct Edge{int to, nxt;int d;}e[MAX];
int head[MAX], rh[MAX], idx;
void add(int head[], int u, int v, int d) {e[++idx].to = v, e[idx].nxt = head[u], head[u] = idx, e[idx].d = d;}
struct Node {int u, d, g;bool operator < (const Node &x)const {return x.d + x.g < g + d;}};
int inq[MAX];
int dis[MAX];
int s, en, k;
void spfa()
{
memset(dis, 0x3f, sizeof (dis));
dis[en] = 0;
queue<int> Q;
Q.push(en);
while (!Q.empty()) {
int u = Q.front(); Q.pop();
inq[u] = 0;
for (int i = rh[u]; i; i = e[i].nxt) {
int v = e[i].to;int d = e[i].d;
if (dis[v] > dis[u] + d) {
dis[v] = dis[u] + d;
if (!inq[v]) {
inq[v] = 1;Q.push(v);
}
}
}
}
}
int cnt[MAX];
int dijkstra()
{
priority_queue<Node> Q;
Node st;st.g = dis[s], st.d = 0, st.u = s;
Q.push(st);
if (dis[s] == 0x3f3f3f3f) return -1;
while (!Q.empty()) {
Node q = Q.top(); Q.pop();
int u = q.u, d = q.d;
cnt[u]++;
if (cnt[en] == k) return d;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to, dd = e[i].d;
if (cnt[v] < k) {Q.push({v, d + dd, dis[v]});}
}
}
return -1;
}
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= m ;i++) {
int u, v, d;
cin >> u >> v >> d;
add(head, u, v, d);
add(rh, v, u, d);
}
cin >> s >> en >> k;
if (s == en) k++;
spfa();
printf("%d", dijkstra());
return 0;
}
最短路计数
#include<bits/stdc++.h>
using namespace std;
#define sf(x) scanf("%d", &x)
#define pf(x) printf("%d\n", x)
typedef long long ll;
const int MAX = 2e6+10;
const int MOD = 100003;
int n, m;
int head[MAX], idx;
struct Edge{
int to, nxt;
}edges[MAX * 3];
void add(int u, int v)
{
edges[++idx].to = v, edges[idx].nxt = head[u], head[u] = idx;
edges[++idx].to = u, edges[idx].nxt = head[v], head[v] = idx;
}
int dis[MAX], ans[MAX], vis[MAX];
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int u, v;
sf(u), sf(v);
add(u, v);
}
queue<int>Q;
Q.push(1);
dis[1] = 1, ans[1] = 1, vis[1] = 1;
while(!Q.empty()) {
int x = Q.front(); Q.pop();
for (int i = head[x]; i; i = edges[i].nxt) {
int y = edges[i].to;
if (!vis[y]){dis[y] = dis[x] + 1; vis[y] = 1; Q.push(y);}
if (dis[y] == dis[x] + 1) {ans[y] = (ans[y] + ans[x]) % MOD;}
}
}
for (int i = 1; i <= n; i++) pf(ans[i]);
return 0;
}
johnson全源最短路
//https://www.luogu.com.cn/problem/P5905
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e5+10;
ll n, m, head[MAX], idx, vis[MAX], h[MAX], dis[MAX], num[MAX], inq[MAX];
struct Edge{ll to, nxt, d;}e[MAX];
void add(ll u, ll v, ll d) {e[++idx].to = v, e[idx].nxt = head[u], e[idx].d = d, head[u] = idx;}
bool spfa(ll st)
{
queue<ll>Q;
//memset(h, 0x3f, sizeof (h));
for (int i = 0; i <= n; i++) h[i] = 0x7fffffff;
h[st] = 0;
Q.push(st);
inq[st] = 1;
while (!Q.empty()) {
ll u = Q.front(); Q.pop();
inq[u] = 0;
for (int i = head[u]; i; i = e[i].nxt) {
ll v = e[i].to, d = e[i].d;
if (h[v] > h[u] + d) {
h[v] = h[u] + d;
num[v]++;
if (num[v] >= n + 1 ) return false;
if (!inq[v]) {Q.push(v); inq[v] = 1;}
}
}
}
return true;
}
struct Node{ll u, d; bool operator < (const Node &x) const{return x.d < d;}};
void dijkstra(int st)
{
for (int i = 1; i <= n; i++) dis[i] = 1000000000;
memset(vis, 0, sizeof (vis));
priority_queue<Node> Q;
dis[st] = 0;
Q.push({st, 0});
while (!Q.empty()) {
Node q = Q.top(); Q.pop();
int u = q.u;
if (vis[u])continue;
vis[u] = 1;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to, d = e[i].d;
if(dis[v] > dis[u] + d) {
dis[v] = dis[u] + d;
Q.push({v, dis[v]});
}
}
}
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int u, v, d;
cin >> u >> v >> d;
add(u, v, d);
}
for (int i = 1; i <= n; i++) {add(0, i, 0);}
if (!spfa(0)) {cout << -1 << endl;return 0;}
for (int i = 1; i <= n; i++) {
for (int j = head[i]; j; j = e[j].nxt) {
e[j].d += h[i] - h[e[j].to];
}
}
for (int i = 1; i <= n; i++) {
dijkstra(i);
ll ans = 0;
for (int j = 1; j <= n; j++) {
if (dis[j] == 1000000000) {ans += dis[j] * j;}
else ans = ans + j * (dis[j] + h[j] - h[i]);
}
cout << ans << endl;
}
return 0;
}
含负权的单源最短路 Bellman-Ford算法
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x7fffffff;
const int MAX = 2e5 +10;
const int M = 5e5+10;
int cnt;
int head[MAX], num[MAX], d[MAX], inq[M], p[MAX];
int n, m;
struct Edge{
int nxt, to, dis;
}e[MAX];
void ADD(int u, int v, int d)
{
e[++cnt].to = v;
e[cnt].nxt = head[u];
e[cnt].dis = d;
head[u] = cnt;
}
bool Bellman_Ford(int s)
{
queue<int>Q;
memset(inq, 0, sizeof(inq));
memset(num, 0, sizeof(num));
Q.push(s);
for(int i = 0; i <= n; i++ ) d[i] = INF;
d[s] = 0;
inq[s] = 1;
while (!Q.empty()) {
int u = Q.front(); Q.pop();
inq[u] = 0;
for (int i = head[u]; i; i = e[i].nxt) {
Edge& a = e[i];
if (d[u] < INF && d[a.to] > d[u] + a.dis) {
d[a.to] = d[u] + a.dis;
p[a.to] = i;
num[a.to]++;
if(num[a.to] >= n) return false;
if (!inq[a.to]) {Q.push(a.to); inq[a.to] = 1; }
}
}
}
return true;
}
int main()
{
int s;
while (cin >> n >> m >> s) {
if (n == 0) break;
for (int i = 0; i < m; i++) {
int from, to, dis;
cin >> from >> to >> dis;
ADD(from, to, dis);
}
if (!Bellman_Ford(s)){
cout << "NO";
}
else {
for (int i = 1; i <= n; i++) cout << d[i] << " ";
}
cout << endl;
}
return 0;
}
差分约束系统
///https://www.luogu.com.cn/problem/P5960
#include<bits/stdc++.h>
using namespace std;
const int MAX = 1e4+10;
int n, m;
int head[MAX], idx, dis[MAX], num[MAX], inq[MAX], vis[MAX];
struct Edge{int to, nxt, d;}edges[MAX];
void add(int u, int v, int d) {edges[++idx].to = v, edges[idx].nxt = head[u], edges[idx].d = d, head[u] = idx;}
bool spfa(int st)
{
queue<int> Q;
Q.push(st);
memset(dis, -1, sizeof(dis));
dis[st] = 0;
inq[st] = 1;
while (!Q.empty()) {
int u = Q.front(); Q.pop();
inq[u] = 0;
for (int i = head[u]; i; i= edges[i].nxt) {
int v = edges[i].to, d = edges[i].d;
if (dis[v] < dis[u] + d) {
dis[v] = dis[u] + d;
num[v]++;
if (num[v] >= n + 1) return true;
if (!inq[v]) {Q.push(v);inq[v] = 1;}
}
}
}
return false;
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int u, v, d;
cin >> u >> v >> d;
add(u, v, -d);
}
for (int i = 1; i<= n; i++) add(0, i, 0);
if (spfa(0)) {cout << "NO" << endl;}
else for (int i = 1; i <= n; i++) {cout << dis[i] << ' ';}cout << endl;
return 0;
}
Bellman_Ford 判断负环存在
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5+10;
const int INF = 0x3f3f3f3f;
int dis[MAX];
int head[MAX];
int cnt;
struct Edge {
int to, nxt, dis;
}edges[MAX];
void add(int u, int v, int d)
{
edges[++cnt].to = v;
edges[cnt].nxt = head[u];
edges[cnt].dis = d;
head[u] = cnt;
}
int n, m;
int inf[MAX];
int num[MAX];
bool spfa(int u)
{
queue<int> Q;
for (int i = 1; i <= n; i++) Q.push(i);
while(!Q.empty()) {
int q = Q.front(); Q.pop();
inf[q] = 0;
for (int i = head[q]; i; i = edges[i].nxt) {
Edge &e = edges[i];
if (dis[q] + e.dis < dis[e.to]) {
dis[e.to] = dis[q] + e.dis;
num[e.to] = num[q] + 1;
if (num[e.to] >= n) return false;
if (!inf[e.to]) {Q.push(e.to); inf[e.to] = 1; }
}
}
}
return true;
}
int main()
{
cin >> n >> m;
for (int i = 0; i < m; i++) {
int u, v, d;
cin >> u >> v >> d;
add(u, v, d);
}
if(!spfa(1)) cout << "Yes";
else cout << "No";
return 0;
}
Bellman_Ford 有边数限制的最短路
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5+10;
const int INF = 0x3f3f3f3f;
struct Edge{
int from, to, dis;
}edges[MAX];
int n, m, k;
int dis[MAX];
int backup[MAX];
bool Bellman_Ford()
{
memset(dis, 0x3f, sizeof(dis));
dis[1] = 0;
for (int i = 0; i < k; i++) {
memcpy(backup, dis, sizeof(dis));
for (int j = 0 ; j < m; j++) {
int f = edges[j].from, t = edges[j].to, d = edges[j].dis;
dis[t] = min(dis[t], backup[f] + d);
}
}
if (dis[n] > (INF / 2)) return false;
else return true;
}
int main()
{
cin >> n >> m >> k;
for(int i = 0; i < m; i++) {
int u, v, d;
cin >> u >> v >> d;
edges[i] = {u, v, d};
}
if(!Bellman_Ford()) cout << "impossible";
else cout << dis[n];
return 0;
}
无向图的最小环问题(路径输出)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = 1e13;
ll d[1005][1005], ori[1005][1005], p[1005][1005];
vector<ll> G;
void dfs(ll i, ll j)
{
ll k = p[i][j];
if (!k) return;
dfs(i, k);
G.push_back(k);
dfs(k, j);
}
void push(ll i, ll j, ll k)
{
G.clear();
G.push_back(k);
G.push_back(i);
dfs(i, j);
G.push_back(j);
}
int main()
{
ll n, m, s;
cin >> n >> m;
for (ll i = 1; i <= n; i++) {
for (ll j = 1; j <= n; j++) {
d[i][j] = ori[i][j] = INF;
}
}
for (ll i = 1; i <= n; i++) d[i][i] = ori[i][i] = 0;
for (ll i = 0; i < m; i++) {
ll u, v, dd;
cin >> u >> v >> dd;
d[u][v] = d[v][u] = ori[u][v] = ori[v][u] = min(d[u][v], dd);
}
ll ans = INF;
for (ll k = 1; k <= n; k++) {
for (ll i = 1; i < k; i++) {
for (ll j = i + 1; j < k; j++) {
if (ans > d[i][j] + ori[i][k] + ori[k][j]) {
ans = d[i][j] + ori[i][k] + ori[k][j];
push(i, j, k);
}
}
}
for (ll i = 1; i <= n; i++) {
for (ll j = 1; j <= n; j++) {
if (d[i][j] > d[i][k] + d[k][j]) {
d[i][j] = d[i][k] + d[k][j];
p[i][j] = k;
}
}
}
}
if (ans == INF) cout << "No solution.";
else for (ll i = 0; i < G.size(); i++) cout << G[i] << ' ';
return 0;
}
欧拉回路
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10, M = 4e5+10;
int head[N], idx = 1;
struct Edge{int to, nxt;}e[M];
void add(int u, int v) {e[++idx].to = v, e[idx].nxt = head[u], head[u] = idx;}
int used[M], ans[M >> 1], cnt, op, n, m, din[N], dout[N];
void dfs(int u)
{
for (int &i = head[u]; i; i = e[i].nxt) {
if (used[i]) {continue;}
used[i] = 1;
if (op == 1) {used[i ^ 1] = 1;}
int t;
if (op == 1) {
t = i / 2;
if (i % 2) t = -t;
}else t = i - 1;
int v = e[i].to;
dfs(v);
ans[cnt++] = t;
}
}
int main()
{
cin >> op;
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
add(u, v);
if (op == 1) add(v, u);
din[v]++, dout[u]++;
}
if (op == 1) {
for (int i = 1; i <= n; i++) {
if (dout[i] + din[i] & 1) {cout << "NO";return 0;}
}
}else {
for (int i = 1; i <= n; i++) {
if (din[i] != dout[i]) {cout << "NO"; return 0;}
}
}
for (int i = 1; i <= n; i++) {
if (head[i]) {dfs(i); break;}
}
if (cnt < m) {cout << "NO"; return 0;}
cout << "YES" <<endl;
for (int i = cnt - 1; i >= 0; i--) cout << ans[i] << ' ';
return 0;
}
割点 并求点双连通分量
dfn为该点的dfs序,low为这个点能够回到的最小的dfs序,如果一个点能够从它的非父亲节点回到dfs序更小的点,则该点不为割点,桥同理
///https://www.luogu.com.cn/problem/P3388
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
ll head[505], idx;
struct Edge{ll to, nxt;}e[10010];
void add(ll u, ll v) {e[++idx].to = v, e[idx].nxt = head[u], head[u] = idx;}
ll dfn[505], low[505], dfscnt, stac[505], top, idcnt, cut[505];
vector<ll> dcc[505];
void tanjan(ll u, ll root)
{
dfn[u] = low[u] = ++dfscnt;
stac[++top] = u;
ll child = 0;
if (u == root && head[u] == 0) {
idcnt++;
dcc[idcnt].push_back(u);
return;
}
for (ll i = head[u]; i; i = e[i].nxt) {
ll v = e[i].to;
if (!dfn[v]) {
tanjan(v, root);
low[u] = min(low[u], low[v]);
if(dfn[u] <= low[v]) {
child ++;
if (u != root || child > 1) cut[u] = 1;
++idcnt;
ll x;
while (x = stac[top--]) {
dcc[idcnt].push_back(x);
if (x == v) break;
}
dcc[idcnt].push_back(u);
}
}else low[u] = min(low[u], dfn[v]);
}
}
int main()
{
ll tt = 1, n;
while (cin >> n && n) {
map<ll, ll>mp;
ll m = 0;
for (int i = 1; i <= idcnt; i++) dcc[i].clear();
memset(dfn, 0, sizeof (dfn));memset(low, 0, sizeof (low)), dfscnt = 0, top = 0, idcnt = 0, memset(head, 0, sizeof (head)), idx = 0, memset(cut, 0, sizeof(cut));
for (ll i = 1; i <= n; i++) {
ll u, v;
cin >> u >> v;
m = max(m, max(u, v));
add(u, v), add(v, u);
}
for (ll i = 1; i <= m; i++) {
if (!dfn[i]) {
tanjan(i, i);
}
}
ll ans1 = 0, ans2 = 1;
for (ll i = 1; i <= idcnt; i++) {
ll Cut = 0;
for (ll j = 0; j < dcc[i].size(); j++) {
if (cut[dcc[i][j]]) Cut++;
}
if (Cut == 0) {
if(dcc[i].size() > 1) ans1 += 2, ans2 = ans2 * (dcc[i].size() * (dcc[i].size() - 1) / 2);
else ans1++;
}else if (Cut == 1) {ans1++, ans2 = ans2 * (dcc[i].size() - 1);}
}
cout << "Case " << tt++ << ": " << ans1 << ' ' << ans2 << endl;
}
return 0;
}
桥
如果边(u,v)代表从u到v有一条边,则如果v的low大于u的dfs序,则该边为桥
///https://www.luogu.com.cn/problem/UVA796
#include<bits/stdc++.h>
using namespace std;
#define PII pair<int,int>
const int MAX = 5e5+10;
int head[100005], idx, dfn[100005], low[100005], tim;
struct Edge{
int to, nxt;
}edges[MAX << 1];
void add(int u, int v){edges[++idx].to = v, edges[idx].nxt = head[u], head[u] = idx;}
struct Cut {int u, v;}cut[MAX];int cut_num;
void tanjan(int u, int fa)
{
dfn[u] = low[u] = ++tim;
for(int i = head[u]; i; i = edges[i].nxt) {
int v = edges[i].to;
if (!dfn[v]) {
tanjan(v, u);
low[u] = min(low[u], low[v]);
if (low[v] > dfn[u]) {
cut[cut_num].u = min(u, v);cut[cut_num++].v = max(u, v);
}
}
else if (v != fa)low[u] = min(low[u], dfn[v]);
}
}
bool cmp(Cut a, Cut b) {if (a.u == b.u) return a.v < b.v; return a.u < b.u;}
int main()
{
int t;
while (cin >> t) {
tim = 0;
memset(dfn, 0, sizeof (dfn)); memset(low, 0, sizeof (low)); memset(head, 0, sizeof (head));
idx = 0; cut_num = 0;
for (int i = 0; i < t; i++) {
int num; char a; char b; int u;
cin >> u >> a >> num >> b;
for (int j = 0; j < num; j++) {
int v;
cin >> v;
v++;
add(u + 1, v);
}
}
for (int i = 1; i <= t; i++) {
if(!dfn[i]) {
tanjan(i, 0);
}
}
sort(cut, cut + cut_num, cmp);
cout << cut_num << " critical links" << endl;
for (int i = 0; i < cut_num; i++) {
cout << cut[i].u - 1 << " - " << cut[i].v - 1 << endl;
}
cout << endl;
}
return 0;
}
缩点
///https://www.luogu.com.cn/problem/P3387
#include<bits/stdc++.h>
using namespace std;
const int MAX = 1e5+10;
int n, m, tim;
int dfn[MAX], low[MAX];
struct Edge{
int from, to, nxt;
}edges[MAX << 1], e[MAX << 1];
int head[MAX], idx, h[MAX];
int in[MAX], ans[MAX];
void add(int u, int v){edges[++idx].to = v, edges[idx].from = u, edges[idx].nxt = head[u], head[u] = idx;}
int len;
int d[MAX];
int stac[MAX], vis[MAX], cir[MAX];
void tanjan(int u)
{
dfn[u] = low[u] = ++tim;
stac[++len] = u; vis[u] = 1;
for (int i = head[u]; i; i = edges[i].nxt) {
int v = edges[i].to;
if (!dfn[v]) {
tanjan(v);
low[u] = min(low[u], low[v]);
} else if (vis[v]) {low[u] = min(low[u], low[v]);}
}
if (dfn[u] == low[u]) {
int v;
while (v = stac[len--]) {
cir[v] = u;
vis[v] = 0;
if(u == v) break;
d[u] += d[v];
}
}
}
int topo()
{
queue<int> Q;
for (int i = 1; i <= n; i++) {
if (cir[i] == i && !in[i]) {Q.push(i); ans[i] = d[i];}
}
while (!Q.empty()) {
int u = Q.front(); Q.pop();
for (int i = h[u]; i; i = e[i].nxt) {
int v = e[i].to;
ans[v] = max(ans[v], ans[u] + d[v]);
in[v]--;
if (!in[v]) Q.push(v);
}
}
int a = 0;
for (int i = 1; i <= n; i++) a = max(a, ans[i]);
return a;
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> d[i];
for(int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
add(u, v);
}
for(int i = 1; i <= n; i++) {
if(!dfn[i]) tanjan(i);
}
idx = 0;
for(int i = 1; i <= m; i++) {
int u = cir[edges[i].from], v = cir[edges[i].to];
if (u == v) continue;
e[++idx].to = v, e[idx].nxt = h[u], h[u] = idx;in[v]++;
}
cout << topo() << endl;
return 0;
}
最大半(弱)连通子图
tanjan缩点后块序号就是topo序
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e6+10;
int head[100010], idx, rh[100010];
struct Edge{int to, nxt, from;}e[MAX];
void add(int u, int v, int head[]) {e[++idx].to = v, e[idx].from = u, e[idx].nxt = head[u], head[u] = idx;}
int dfn[100010], low[100010], dfscnt, vis[100010], stac[100010], top, id[100010], num[100010], idcnt;
int n, m, x;
int f[100010], g[100010];
void tanjan(int u)
{
dfn[u] = low[u] = ++dfscnt;
vis[u] = 1; stac[++top] = u;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (!dfn[v]) tanjan(v);
if (vis[v]) low[u] = min(low[u], low[v]);
}
if (low[u] == dfn[u]) {
int v;
idcnt++;
while (v = stac[top--]) {
id[v] = idcnt;
num[id[v]]++;
vis[v] = 0;
if (u == v) break;
}
}
}
unordered_map<ll, int> mp;
int main()
{
cin >> n >> m >> x;
for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
add(u, v, head);
}
for (int i = 1; i <= n; i++) {
if (!dfn[i]) tanjan(i);
}
for (int i = 1; i <= m; i++) {
int u = e[i].from, v = e[i].to;
if (id[u] == id[v]) continue;
if (mp[id[u]*1000010 + id[v]]) continue;
mp[id[u]*1000010 + id[v]] = 1;
add(id[u], id[v], rh);
}
for (int i = idcnt; i; i--) {
if (!f[i]) {
f[i] = num[i]; g[i] = 1;
}
for (int j = rh[i]; j; j = e[j].nxt) {
int v = e[j].to;
if (f[v] < f[i] + num[v]) {
f[v] = f[i] + num[v];
g[v] = g[i];
}
else if (f[v] == f[i] + num[v]) g[v] = (g[v] + g[i]) % x;
}
}
int maxn = 0, sum = 0;
for (int i = 1; i <= idcnt; i++) {
if (f[i] > maxn) maxn = f[i], sum = g[i];
else if (f[i] == maxn) sum = (sum + g[i]) % x;
}
cout << maxn << endl << sum << endl;
return 0;
}
LCA倍增
#include<iostream>
#include<algorithm>
using namespace std;
#define MAX 500005
struct Tree{
int now;
int nxt;
}my[500010 << 1];
int head[MAX], flag, lg[MAX], depth[MAX], father[MAX][30];
void add(int a, int b)
{
my[++flag].now = b;
my[flag].nxt = head[a];
head[a] = flag;
}
void BuildTree(int now, int fa)
{
father[now][0] = fa;
depth[now] = depth[fa] + 1;
for (int i = 1; i <= lg[depth[now]]; i++) {
father[now][i] = father[father[now][i - 1]][i - 1];
}
for (int i = head[now]; i; i = my[i].nxt) {
if (my[i].now != fa) BuildTree(my[i].now, now);
}
}
int LCA(int x, int y)
{
if (depth[x] < depth[y]) swap(x, y);
while (depth[x] > depth[y]) {x = father[x][lg[depth[x] - depth[y]] - 1];}
if (x == y) return x;
for (int i = lg[depth[x]] - 1; i >= 0; i--) {
if (father[x][i] != father[y][i]) x = father[x][i], y = father[y][i];
}
return father[x][0];
}
int main()
{
int n, m, s;
cin >> n >> m >> s;
for (int i = 1; i < n; i++) {
int x, y;
cin >> x >> y;
ada(x, y);
add(y, x);
}
for (int i = 1; i <= n; i++) { ///预先算出log_2(i)+1的值
lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);///常数优化预处理,此操作为求出log2(i)的大小
}
BuildTree(s, 0);
for (int i = 1; i <= m; i++) {
int a, b;
cin >> a >> b;
cout << LCA(a, b) << endl;
}
return 0;
}
树上差分
#include<bits/stdc++.h>
using namespace std;
const int MAX = 6e5+10;
int head[100010], idx, fa[100010][34], dep[100010], p[100010], lg[100010];
struct Edge{int to, nxt;}e[MAX];
void add(int u, int v) {e[++idx].to = v, e[idx].nxt = head[u], head[u] = idx;}
int n, m;
void build(int u, int f)
{
fa[u][0] = f;
dep[u] = dep[f] + 1;
for (int i = 1; i <= lg[dep[u]]; i++) {fa[u][i] = fa[fa[u][i - 1]][i - 1];}
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v != f) build(v, u);
}
}
int LCA (int x, int y)
{
if (dep[x] < dep[y]) swap(x, y);
while (dep[x] > dep[y]) {x = fa[x][lg[dep[x] - dep[y]] - 1];}
if (x == y) return x;
for (int i = lg[dep[x]] - 1; i >= 0; i--) {
if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
}
return fa[x][0];
}
void dfs(int u, int f)
{
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v == f) continue;
dfs(v, u);
p[u] += p[v];
}
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++) lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
add(u, v), add(v, u);
}
build(1, 0);
for (int i = 1; i <= m; i++) {
int a, b;
cin >> a >> b;
p[a]++, p[b]++;
p[LCA(a, b)] -= 2;
}
dfs(1, 0);
int ans = 0;
for (int i = 2; i <= n; i++) {
if (!p[i]) ans += m;
if (p[i] == 1) ans++;
}
cout << ans;
return 0;
}
LCA树剖
#include<bits/stdc++.h>
using namespace std;
const int MAX = 1e6+10;
int top[MAX], son[MAX], dfs_clock[MAX], fa[MAX], siz[MAX], dep[MAX];
int head[MAX], idx;
struct Edge{int to, nxt;}e[MAX << 1];
void add(int u, int v) {e[++idx].to = v, e[idx].nxt = head[u], head[u] = idx;}
int n, m, s;
int cnt;
void dfs1(int u, int f)
{
son[u] = -1;
siz[u] = 1;
dep[u] = dep[f] + 1;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v == f) continue;
fa[v] = u;
dfs1(v, u);
siz[u] += siz[v];
if (son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v;
}
}
void dfs2(int u, int t)
{
top[u] = t;
cnt++;
dfs_clock[u] = cnt;
if (son[u] == -1) return;
dfs2(son[u], t);
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v != son[u] && v != fa[u]) dfs2(v, v);
}
}
int LCA(int x, int y)
{
while (top[x] != top[y]) {
if (dep[top[x]] > dep[top[y]]) x = fa[top[x]];
else y = fa[top[y]];
}
return dep[x] > dep[y] ? y : x;
}
int main()
{
cin >> n >> m >> s;
for (int i = 1; i < n; i++) {int u, v; cin >> u >> v; add(u, v), add(v, u);}
dfs1(s, 0);
dfs2(s, s);
while (m--) {
int x, y;
cin >> x >> y;
cout << LCA(x, y) << endl;
}
return 0;
}
虚树
//https://www.luogu.com.cn/problem/P2495
//https://oi-wiki.org/graph/virtual-tree/
//虚树
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e6+10;
ll head[500050], idx, fa[500050][33], dep[500050], head1[500050], idx1, stac[500050], top;
ll query[500050], dfncnt, dfn[500050], lg[500050], minn[500050], h[500050];
struct Edge{ll to, nxt, d;}e[MAX], e1[MAX];
void add(ll u, ll v, ll d) {e[++idx].to = v, e[idx].nxt = head[u], e[idx].d = d, head[u] = idx;}
void vadd(ll u, ll v) {e1[++idx1].to = v, e1[idx1].nxt = head1[u], head1[u] = idx1;}
ll n, m;
void dfs(ll u, ll f)
{
fa[u][0] = f;
dep[u] = dep[f] + 1;
dfn[u] = ++dfncnt;
for (ll i = 1; i <= lg[dep[u]]; i++) {fa[u][i] = fa[fa[u][i - 1]][i - 1];}
for (ll i = head[u]; i; i = e[i].nxt) {
ll v = e[i].to;
if (v == f) continue;
minn[v] = min(minn[u], e[i].d);
dfs(v, u);
}
}
ll LCA (ll x, ll y)
{
if (dep[x] < dep[y]) swap(x, y);
while (dep[x] > dep[y]) x = fa[x][lg[dep[x] - dep[y]] - 1];
if (x == y) return x;
for (ll i = lg[dep[x] - 1]; i >= 0; i--) {
if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
}
return fa[x][0];
}
ll dp(ll u)
{
ll sum = 0, tmp;
for (ll i = head1[u]; i; i = e1[i].nxt) {
ll v = e1[i].to;
sum += dp(v);
}
if (query[u]) tmp = minn[u];
else tmp = min(minn[u], sum);
query[u] = 0;head1[u] = 0;
return tmp;
}
bool cmp(ll a, ll b){return dfn[a] < dfn[b];}
int main()
{
cin >> n;
minn[1] = 2147483647000000;
for (ll i = 1; i <= n; i++) lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
for (ll i = 1; i < n; i++) {
ll u, v, d;
cin >> u >> v >> d;
add(u, v, d), add(v, u, d);
}
dfs(1, 0);
cin >> m;
while (m--) {
idx1 = 0;
ll k;
cin >> k;
for (ll i = 1; i <= k; i++) {cin >> h[i];query[h[i]] = 1;}
sort(h + 1, h + 1 + k, cmp);
stac[top = 1] = 1;
for (ll i = 1; i <= k; i++) {
if (h[i] == 1) continue;
ll now = h[i];
ll lca = LCA(now, stac[top]);
if (lca != stac[top]) {
while (dfn[lca] < dfn[stac[top - 1]]) {
vadd(stac[top - 1], stac[top]), top--;
}
if (lca != stac[top - 1]) {
head1[lca] = 0; vadd(lca, stac[top]); stac[top] = lca;
}else vadd(lca, stac[top--]);
}
head1[now] = 0, stac[++top] = now;
}
for (ll i = 1; i < top; i++) {vadd(stac[i], stac[i + 1]);}
cout << dp(1) << endl;
}
return 0;
}
Kruskal最小生成树
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 5e3+10;
int fa[MAX];
int n, m;
struct Edge {int from, to, w;}a[200005];
bool cmp(Edge A, Edge B){ return A.w < B.w;}
void ori(){ for (int i = 1; i <= n; i++) fa[i] = i;}
int find(int u){return u == fa[u] ? u : fa[u] = find(fa[u]);}
int ans = 0;
void Kruskal()
{
sort(a + 1, a + 1 + m, cmp);
for (int i = 1; i <= m; i++) {
int x = a[i].from, y = a[i].to;
x = find(x), y = find(y);
if (x == y) continue;
fa[x] = y;
ans += a[i].w;
}
}
int main()
{
cin >> n >> m;
ori();
for (int i = 1; i <= m; i++) {
cin >> a[i].from >> a[i].to >> a[i].w;
}
Kruskal();
cout << ans << endl;
return 0;
}
严格次小生成树
///https://www.luogu.com.cn/problem/P4180
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 6e5+10;
const ll INF = 2147483647000000;
ll ans = 0;
ll head[MAX], idx, dep[MAX], fa[MAX][35], num, lg[MAX], w1[MAX][35], w2[MAX][35], f[MAX];
struct Kruskal{ll u, v, d;}a[600010], mytry[600010];
struct Edge{ll to, nxt, d;}e[800010];
void add(ll u, ll v, ll d){e[++idx].to = v, e[idx].nxt = head[u], e[idx].d = d, head[u] = idx;}
bool cmp(Kruskal a, Kruskal b) {return a.d < b.d;}
ll find(ll n) {return n == f[n] ? n : f[n] = find(f[n]);}
void kruskal(ll m)
{
sort(a + 1, a + m + 1, cmp);
for (ll i = 1; i <= m; i++) {
ll u = a[i].u, v = a[i].v;
u = find(u), v = find(v);
if (u == v) {mytry[++num] = a[i];continue;}
f[u] = v;
ans += a[i].d;
add(a[i].u, a[i].v, a[i].d), add(a[i].v, a[i].u, a[i].d);
}
}
void dfs(ll u, ll ff)
{
dep[u] = dep[ff] + 1;
fa[u][0] = ff;
for (ll i = 1; i <= lg[dep[u]]; i++) {
fa[u][i] = fa[fa[u][i - 1]][i - 1];
w1[u][i] = max(w1[u][i - 1], w1[fa[u][i - 1]][i - 1]);
w2[u][i] = max(w2[u][i - 1], w2[fa[u][i - 1]][i - 1]);
if (w1[u][i - 1] < w1[fa[u][i - 1]][i - 1]) w2[u][i] = max(w2[u][i], w1[u][i - 1]);
else if (w1[u][i - 1] > w1[fa[u][i - 1]][i - 1]) w2[u][i] = max(w2[u][i], w1[fa[u][i - 1]][i - 1]);
}
for (ll i = head[u]; i; i = e[i].nxt) {
ll v = e[i].to;
if (v == ff) continue;
w1[v][0] = e[i].d;
w2[v][0] = -INF;
dfs(v, u);
}
}
ll LCA(ll x, ll y)
{
if (dep[x] < dep[y]) swap(x, y);
while (dep[x] > dep[y]) { x = fa[x][lg[dep[x] - dep[y]] - 1];}
if (x == y) return x;
for (ll i = lg[dep[x]] - 1; i >= 0; i--) {if (fa[x][i] != fa[y][i]) {x = fa[x][i], y = fa[y][i];}}
return fa[x][0];
}
ll cal(ll u, ll v, ll d)
{
ll ans = -INF;
while(dep[u] > dep[v]) {
if (d == w1[u][lg[dep[u] - dep[v]] - 1]) ans = max(ans, w2[u][lg[dep[u] - dep[v]] - 1]);
else ans = max(ans, w1[u][lg[dep[u] - dep[v]] - 1]);
u = fa[u][lg[dep[u] - dep[v]] - 1];
}
return ans;
}
int main()
{
ll n, m;
cin >> n >> m;
for (ll i = 1; i <= n; i++) lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
for (ll i = 1; i <= n; i++) f[i] = i;
for (ll i = 1; i <= m; i++) {
ll u, v, d;
cin >> u >> v >> d;
a[i] = {u, v, d};
}
kruskal(m);
w2[1][0] = -INF;
dfs(1, 0);
ll res = INF;
for (ll i = 1; i <= num; i++) {
ll u = mytry[i].u, v = mytry[i].v;
ll l = LCA(u, v);
ll max1 = cal(u, l, mytry[i].d);
ll max2 = cal(v, l, mytry[i].d);
res = min(res, ans - max(max1, max2) + mytry[i].d);
}
cout << res;
return 0;
}
最大流 ISAP算法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = 2147483647000000;
const int N = 20005, M = 100010;
struct Edge{ll to, nxt, d;}e[M];
ll head[N], idx = 1;
void add(ll u, ll v, ll d) {e[++idx].to = v, e[idx].nxt = head[u], e[idx].d = d, head[u] = idx;}
ll dep[N], gap[N], cur[N];
ll n, m, s, t;
ll maxflow;
void bfs()
{
memset(dep, -1, sizeof(dep));
memset(gap, 0, sizeof (gap));
dep[t] = 0;
gap[0] = 1;
queue<ll> Q;
Q.push(t);
while (!Q.empty()) {
ll u = Q.front(); Q.pop();
for (ll i = head[u]; i; i = e[i].nxt) {
ll v = e[i].to;
if (dep[v] != -1) continue;
dep[v] = dep[u] + 1;
gap[dep[v]]++;
Q.push(v);
}
}
}
ll dfs(ll u, ll flow)
{
if (u == t) {
maxflow += flow;
return flow;
}
ll used = 0;
for (ll& i = cur[u]; i; i = e[i].nxt) {
ll v = e[i].to, d = e[i].d;
if (d && dep[v] + 1 == dep[u]) {
ll mi = dfs(v, min(flow - used, d));
if(mi) {
e[i].d -= mi;
e[i ^ 1].d += mi;
used += mi;
}
if (used == flow) return used;
}
}
gap[dep[u]]--;
if (gap[dep[u]] == 0) dep[s] = N + 1;
dep[u]++;
gap[dep[u]]++;
return used;
}
ll ISAP()
{
maxflow = 0;
bfs();
while (dep[s] < N) {memcpy(cur,head,sizeof(head));dfs(s, INF);}
return maxflow;
}
int main()
{
cin >> n >> m >> s >> t;
for(ll i = 1; i <= m; i++) {
ll u, v, w;
cin >> u >> v >> w;
add(u, v, w), add(v, u, 0);
}
cout << ISAP();
return 0;
}
最小费用最大流 MCMF
#include<bits/stdc++.h>
using namespace std;
const int N = 5e3+10, M = 1e6+10;
int head[N], idx = 1;
struct Edge{int to, nxt, d, c;}e[M];
void add(int u, int v, int d, int c)
{
e[++idx].to = v, e[idx].nxt = head[u], head[u] = idx, e[idx].d = d, e[idx].c = c;
e[++idx].to = u, e[idx].nxt = head[v], head[v] = idx, e[idx].d = 0, e[idx].c = -c;
}
int dis[N], inq[N], incf[N], pre[N], n, m, s, t, maxflow, mincost;
///incf代表当前增广路上最小流量
bool spfa()
{
queue<int> Q;
memset(dis, 0x3f, sizeof (dis));
memset(inq, 0, sizeof (inq));
Q.push(s);
dis[s] = 0;
inq[s] = 1;
incf[s] = 1 << 30;
while (!Q.empty()) {
int u = Q.front(); Q.pop();
inq[u] = 0;
for (int i = head[u]; i; i = e[i].nxt) {
if (!e[i].d) continue;
int v = e[i].to, d = e[i].c;
if (dis[v] > dis[u] + d) {
dis[v] = dis[u] + d;
incf[v] = min(incf[u], e[i].d);
pre[v] = i;
if (!inq[v]) {inq[v] = 1; Q.push(v);}
}
}
}
return dis[t] != 0x3f3f3f3f;
}
void MCMF()
{
while (spfa()) {
int x = t;
maxflow += incf[t];
mincost += dis[t] * incf[t];
int i;
while (x != s) {
i = pre[x];
e[i].d -= incf[t];
e[i ^ 1].d += incf[t];
x = e[i ^ 1].to;
}
}
}
int main()
{
cin >> n >> m >> s >> t;
for (int i = 1; i <= m; i++) {
int u, v, d, c;
cin >> u >> v >> d >> c;
add(u, v, d, c);
}
MCMF();
cout << maxflow << ' ' << mincost;
return 0;
}
树的重心
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAX = 2e5+10;
int n;
int head[MAX];
struct Edge{
int to, nxt;
}edges[MAX];
int cnt;
void add(int u, int v)
{
edges[++cnt].to = v;
edges[cnt].nxt = head[u];
head[u] = cnt;
edges[++cnt].to = u;
edges[cnt].nxt = head[v];
head[v] = cnt;
}
int ans = INF;
int vis[MAX];
int dfs(int u)
{
int res = 0;
int sum = 1;
for (int i = head[u]; i; i = edges[i].nxt) {
int v =edges[i].to;
if (!vis[v]) {
vis[v] = 1;
int s = dfs(v);
res = max(res, s);
sum += s;
}
}
res = max(res, n - sum);
ans = min(ans, res);
return sum;
}
int main()
{
cin >> n;
for (int i = 0; i < n - 1; i++) {
int u, v;
cin >> u >> v;
add(u, v);
}
vis[1] = 1;
dfs(1);
cout << ans;
return 0;
}
图的中心
///https://www.luogu.com.cn/problem/CF266D
///https://oi-wiki.org/graph/mdst/
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX = 205;
int f[MAX][MAX], rk[MAX][MAX], val[MAX];
int n, m;
struct Edge{int u, v, d;}a[100010];
void floyd()
{
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] < INF && f[k][j] < INF) {
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
}
}
}
}
}
bool cmp(int a, int b) {return val[a] < val[b];}
int main()
{
cin >> n >> m;
memset(f, 0x3f, sizeof(f));
for (int i = 1; i <=n; i++) f[i][i] = 0;
for (int i = 1; i <= m; i++) {
cin >> a[i].u >> a[i].v >> a[i].d;
f[a[i].u][a[i].v] = f[a[i].v][a[i].u] = min(f[a[i].u][a[i].v], a[i].d);
}
floyd();
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
rk[i][j] = j; val[j] = f[i][j];
}
sort(rk[i] + 1, rk[i] + 1 + n, cmp);
}
int ansp = INF, ansl = INF;
///绝对中心在点上
for (int i = 1; i <= n; i++) ansp = min(ansp, f[i][rk[i][n]] * 2);
绝对中心在边上
for(int i = 1; i <= m; i++) {
int u = a[i].u, v = a[i].v, d = a[i].d;
for (int p = n, j = n - 1; j >= 1; j--) {
if (f[v][rk[u][j]] > f[v][rk[u][p]]) {
ansl = min(ansl, f[u][rk[u][j]] + f[v][rk[u][p]] + d);
p = j;
}
}
}
printf("%.2lf", 1.0 * min(ansp, ansl) / 2);
return 0;
}
树的直径
///https://www.luogu.com.cn/problem/P5536
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 3e5+10;
struct Edge{
ll to, nxt;
}edges[501100];
ll cnt;
ll head[MAX];
void add(ll u, ll v)
{
edges[++cnt].to = v;
edges[cnt].nxt = head[u];
head[u] = cnt;
edges[++cnt].to = u;
edges[cnt].nxt = head[v];
head[v] = cnt;
}
struct Node {
ll now, steps;
Node(ll n, ll s):now(n), steps(s){}
Node(){}
};
ll fa[MAX];
ll depth[MAX];
ll vis[MAX];
ll len = -1;
ll bfs(ll s)
{
memset(fa, 0, sizeof (fa));
fa[s] = s;
memset(depth, 0, sizeof (depth)); memset(vis, 0, sizeof (vis));
ll last;
ll maxd = 0;
queue<Node> Q;
vis[s] = 1;
depth[s] = 0;
Q.push(Node(s, 0));
while(!Q.empty()) {
Node q = Q.front(); Q.pop();
len = max(len, q.steps);
for (int i = head[q.now]; i; i = edges[i].nxt) {
int to = edges[i].to;
if (vis[to]) continue;
vis[to] = 1;
depth[to] = depth[q.now] + 1;
fa[to] = q.now;
if(maxd < depth[to]) {
last = to;
maxd = depth[to];
}
Q.push(Node(to, q.steps + 1));
}
}
return last;
}
ll maxdepth[MAX];
void dfs(ll now, ll fath)
{
maxdepth[now] = depth[now];
for (ll i = head[now]; i; i = edges[i].nxt) {
ll to = edges[i].to;
if (to == fath) continue;
depth[to] = depth[now] + 1;
dfs(to, now);
maxdepth[now] = max(maxdepth[now], maxdepth[to]);
}
}
ll ans[MAX];
ll Ans;
bool cmp(ll a, ll b)
{
return a > b;
}
int main()
{
ll n, k;
cin >> n >> k;
for(int i = 1; i < n; i++) {
ll u, v;
cin >> u >> v;
add(u, v);
}
ll last = bfs(bfs(1));
ll deep;
ll node = last;
for(ll i = 1; i <= (depth[last] + 1) / 2; i++) node = fa[node];
memset(depth, 0, sizeof (depth));
dfs(node, 0);
for (ll i = 1; i <= n; i++) {
ans[i] = maxdepth[i] - depth[i];
}
sort(ans + 1, ans + 1 + n, cmp);
cout << ans[k + 1] + 1;
return 0;
}
二分图最大匹配
#include<bits/stdc++.h>
using namespace std;
const int MAX = 1e5+10;
int head[505], idx;
struct Edge{int to, nxt;}e[MAX];
void add(int u, int v) {e[++idx].to = v, e[idx].nxt = head[u], head[u] = idx;}
int match[505], vis[505];
bool find(int u)
{
for (int i = head[u]; i; i = e[i].nxt ) {
int v = e[i].to;
if (!vis[v]) {
vis[v] = 1;
if (!match[v] || find(match[v])) {
match[v] = u;
return true;
}
}
}
return false;
}
int n1, n2, m, ans;
int main()
{
cin >> n1 >> n2 >> m;
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
add(u, v);
}
for (int i = 1; i <= n1; i++) {
memset(vis, 0, sizeof (vis));
if (find(i)) ans++;
}
cout << ans;
return 0;
}
DP
有依赖的背包
#include<bits/stdc++.h>
using namespace std;
const int N = 110, M = 1e5+10;
int head[N], idx;
struct Edge{int to, nxt;}e[M];
void add (int u, int v) {e[++idx].to = v, e[idx].nxt = head[u], head[u] = idx;}
int dp[110][10010], v[N], w[N];
int n, m;
void dfs(int u)
{
for (int i = v[u]; i <= m; i++) dp[u][i] = w[u];
for (int i = head[u]; i; i = e[i].nxt) {
int x = e[i].to;
dfs(x);
for (int j = m; j >= v[u]; j--) {
for (int k = 0; k <= j - v[u]; k++) {
dp[u][j] = max(dp[u][j], dp[u][j - k] + dp[x][k]);
}
}
}
}
int main()
{
cin >> n >> m;
int root;
for (int i = 1; i <= n; i++) {
int u;
cin >> v[i] >> w[i] >> u;
if (u != -1) add(u, i);
if (u == -1) root = i;
}
dfs(root);
cout << dp[root][m];
return 0;
}
背包求方案数
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 1000010;
const ll MOD = 1e9+7;
ll dp[N], v[N], w[N], cnt[N];
int main()
{
ll n, m;
cin >> n >> m;
for (int i = 1; i <= m; i++) {
cin >> v[i] >> w[i];
}
for (int i = 0; i <= 1050; i++) cnt[i] = 1;
for (int i = 1; i <= n; i++) {
for (int j = m; j >= v[i]; j--) {
int tmp = dp[j - v[i]] + w[i];
if (tmp > dp[j]) {
dp[j] = tmp;
cnt[j] = cnt[j - v[i]];
}else if (tmp == dp[j]) {
cnt[j] += cnt[j - v[i]];
cnt[j] %= MOD;
}
}
}
cout << cnt[m];
return 0;
}
背包求具体方案
#include<bits/stdc++.h>
using namespace std;
int dp[1010][1010], v[1010], w[1010], n, m;
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> v[i] >> w[i];
for (int i = n; i >= 1; i--) {
for (int j = 0; j <= m; j++) {
dp[i][j] = dp[i + 1][j];
if (j >= v[i]) dp[i][j] = max(dp[i][j], dp[i + 1][j - v[i]] + w[i]);
}
}
int j = m;
for (int i = 1; i <= n; i++) {
if (j >= v[i] && dp[i][j] == dp[i + 1][j - v[i]] + w[i]) {
cout << i << ' ';
j -= v[i];
}
}
return 0;
}
数据结构
KMP
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
char a[10005], b[10005];
int next[10005];
void GetNext(char *p, int next[])
{
int pLen = strlen(p);
next[0] = -1;
int k = -1;
int j = 0;
while (j < pLen - 1) {
if (k == -1 || p[j] == p[k]) {
++j;
++k;
if (p[j] != p[k])
next[j] = k;
else
next[j] = next[k];
}
else {
k = next[k];
}
}
}
int KmpSearch(char* s, char* p)
{
int i = 0;
int j = 0;
int sLen = strlen(s);
int pLen = strlen(p);
while (i < sLen && j < pLen) {
if (j == -1 || s[i] == p[j]) {
i++;
j++;
}
else {
j = next[j];
}
}
if (j == pLen)
return i - j;
else
return -1;
}
int main()
{
cin >> a >> b;
GetNext(b, next);
cout << KmpSearch(a, b);
return 0;
}
ST表
它是解决RMQ问题(区间最值问题)的一种强有力的工具
它可以做到
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)预处理,
O
(
1
)
O(1)
O(1)查询最值
#include<bits/stdc++.h>
using namespace std;
#define sf(x) scanf("%d", &x)
#define pf(x) printf("%d\n", x)
const int MAX = 1e6+10;
int st[MAX][30];
int find(int l, int r)
{
int k = log2(r - l + 1);
return max(st[l][k], st[r - (1 << k) + 1][k]);
}
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i<= n; i++) sf(st[i][0]);
for (int j = 1; j<= 26; j++) {
for (int i = 1; i + (1 << j) - 1 <= n; i++) {
st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
}
while (m--) {
int l, r;
sf(l), sf(r);
pf(find(l ,r));
}
return 0;
}
线段树
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e6+10;
ll a[MAX], tag[MAX << 1], ans[MAX << 1];
ll lt(ll x){return x << 1;}
ll rt(ll x){return x << 1 | 1;}
void push_up(ll x){ans[x] = ans[lt(x)] + ans[rt(x)];}
void build(ll x, ll l, ll r)
{
tag[x] = 0;
if (l == r) {ans[x] = a[l]; return;}
ll mid = l + r >> 1;
build(lt(x), l, mid);
build(rt(x), mid + 1, r);
push_up(x);
}
void f(ll x, ll l, ll r, ll k)
{
tag[x] += k;
ans[x] = ans[x] + k * (r - l + 1);
}
void push_down(ll x, ll l, ll r)
{
ll mid = l + r >> 1;
f(lt(x), l, mid, tag[x]);
f(rt(x), mid + 1, r, tag[x]);
tag[x] = 0;
}
void update(ll nl, ll nr, ll l, ll r, ll x, ll k)
{
if (nl <= l && nr >= r) {
ans[x] += k * (r - l + 1);
tag[x] += k;
return;
}
push_down(x, l, r);
ll mid = l + r >> 1;
if (nl <= mid) {update(nl, nr, l, mid, lt(x), k);}
if (nr > mid) {update(nl, nr, mid + 1, r, rt(x), k);}
push_up(x);
}
ll query(ll nl, ll nr, ll l, ll r, ll x)
{
ll res = 0;
if (nl <= l && nr >= r) return ans[x];
ll mid = l + r >> 1;
push_down(x, l, r);
if (nl <= mid) {res += query(nl, nr, l, mid, lt(x));}
if (nr > mid) {res += query(nl, nr, mid + 1, r, rt(x));}
return res;
}
int main()
{
ll n, m;
cin >> n >> m;
for (ll i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
build(1, 1, n);
while (m--) {
ll op;
scanf("%d", &op);
if (op == 1) {
ll x, y, k;
scanf("%lld%lld%lld", &x, &y, &k);
update(x, y, 1, n, 1, k);
}
else {
ll x, y;
scanf("%lld%lld", &x, &y);
printf("%lld\n", query(x, y, 1, n, 1));
}
}
return 0;
}
字典树
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
const int MAX = 1e5+10;
ll son[MAX * 33][2], idx;
void insert(ll x)
{
ll p = 0;
for (ll len = 31; len >= 0; len--) {
ll y = x >> len & 1;
if (!son[p][y]) son[p][y] = ++idx;
p = son[p][y];
}
}
ll query(ll q)
{
ll p = 0;
ll ans = 0;
for(int len = 31; len >= 0; len--) {
ll y = q >> len & 1;
if (son[p][!y]) {
ans = (ans << 1) + !y;
p = son[p][!y];
}else {
ans = (ans << 1) + y;
p = son[p][y];
}
}
return ans;
}
int main()
{
ll t;
scanf("%lld", &t);
for (ll tt = 1; tt <= t; tt++) {
memset(son, 0, sizeof(son));idx = 0;
ll n, m;
scanf("%lld%lld", &n, &m);
printf("Case #%lld:\n", tt);
for(int i = 1; i <= n; i++) {
ll x;
scanf("%lld", &x);
insert(x);
}
while (m--) {
ll q;
scanf("%lld", &q);
printf("%lld\n", query(q));
}
}
return 0;
}
数论
欧拉筛
void init()
{
for (int i = 1; i < N; i++) phi[i] = i;
for (int i = 2; i < N; i++) {
if (phi[i] == i) {
for (int j = i; j < N; j += i) {
phi[j] = phi[j] / i *(i - 1);
}
}
}
}
容斥原理
复杂度: O ( n 2 n ) O(n2^n) O(n2n)
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 1e9+7;
int a[25], down = 1, n, m;
int ksm(int aa, int b)
{
int ans = 1;
while (b) {
if (b & 1) ans = (ans * aa) % MOD;
aa = (aa * aa) % MOD;
b >>= 1;
}return ans;
}
int C(int aa, int b)
{
if (b > aa)return 0;
int up = 1;
for (int i = aa; i > aa - b; i--) {up = (i % MOD * up % MOD);}
return up * down % MOD;
}
signed main()
{
cin >> n >> m;
for (int i = 0; i < n; i++) {cin >> a[i];}
for (int i = 1; i < n; i++) {
down = (down * i) % MOD;
}
down = ksm(down, MOD - 2);
int ans = 0;
for (int i = 0; i < (1 << n); i++) {
int sign = 1;
int d = m + n - 1, up = n - 1;
for (int j = 0; j < n; j++) {
if (i & (1 << j)) {
sign = -sign;
d -= a[j] + 1;
}
}
ans = (ans + C(d, up) * sign) % MOD;
}cout << (ans + MOD) % MOD;
return 0;
}
线性筛筛莫比乌斯函数
题意:给出abd,求有多少对xy满足, x ≤ a x\le a x≤a, y ≤ b y\le b y≤b,并且 g c d ( x , y ) = d gcd(x,y)=d gcd(x,y)=d
思路:容斥配莫比乌斯函数优化一下
#include<bits/stdc++.h>
using namespace std;
#define sf(x) scanf("%lld", &x)
#define pf(x) printf("%lld\n", x)
#define int long long
const int N = 5e4+10;
int primes[N], cnt;
int st[N];
int mobius[N], sum[N];
/// 线性筛筛莫比乌斯函数
void init(int n)
{
mobius[1] = 1;
for (int i = 2; i <= n; i++) {
if (!st[i]) {
primes[cnt++] = i;
mobius[i] = -1;
}
for (int j = 0; primes[j] * i <= n; j++) {
int t = primes[j] * i;
st[t] = 1;
if (i % primes[j] == 0) {
mobius[t] = 0;
break;
}
mobius[t] = mobius[i] * -1;
}
}
for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + mobius[i];
}
///有个东西,就是[a/x]=[a/g(x)],其中g(x)是满足这个式子的最大的x值,而g(x)=[a/x],这个不会超过根号n,直接枚举每个区间的r
signed main()
{
init(N - 1);
int T;
cin >> T;
while (T--) {
int a, b, d;
sf(a), sf(b), sf(d);
a /= d, b /= d;
int n = min(a, b);
int res = 0;
for (int l = 1, r; l <= n; l = r + 1) {
r = min(n, min(a / (a / l), b / (b / l)));
res += (sum[r] - sum[l - 1]) * (a / l) * (b / l);
}pf(res);
}
return 0;
}
莫比乌斯反演
一:
F ( n ) = ∑ d ∣ n f ( d ) F(n) = \sum_{d|n}f(d) F(n)=∑d∣nf(d)
$\Rightarrow $
f ( n ) = ∑ d ∣ n F ( d ) ∗ μ ( n d ) f(n)=\sum_{d|n}F(d)*μ(\frac{n}{d}) f(n)=∑d∣nF(d)∗μ(dn)
二:
F ( n ) = ∑ n ∣ d f ( d ) F(n)=\sum_{n|d}f(d) F(n)=∑n∣df(d)
$\Rightarrow $
f ( n ) = ∑ n ∣ d μ ( d n ) ∗ F ( d ) f(n)=\sum_{n|d}μ(\frac{d}{n})*F(d) f(n)=∑n∣dμ(nd)∗F(d)
三:
[
g
c
d
(
i
,
j
)
=
1
]
=
∑
d
∣
g
c
d
(
i
,
j
)
μ
(
d
)
[gcd(i,j)=1]=\sum_{d|gcd(i,j)}μ(d)
[gcd(i,j)=1]=∑d∣gcd(i,j)μ(d)
∑ d ∣ n μ ( d ) = [ n = 1 ] \sum_{d|n}μ(d)=[n=1] ∑d∣nμ(d)=[n=1]
Lucas定理
#include<bits/stdc++.h>
#define int long long
int f[200010], Inv[200010];
void solve()
{
int n, m, p;
std::cin >> n >> m >> p;
f[0] = f[1] = 1, Inv[0] = Inv[1] = 1;
for (int i = 2; i <= p; i++) {
f[i] = f[i - 1] * i % p;
Inv[i] = (p - (p / i)) * Inv[p % i] % p;
}
std::function<int(int, int)>C = [&](int m, int n) {
return m < n ? 0ll : f[m] * Inv[f[n]] % p * Inv[f[m - n]] % p;
};
std::function<int(int ,int)>lucas = [&](int m, int n) {
return n == 0 ? 1ll : lucas(m / p, n / p) * C(m % p, n % p) % p;
};
std::cout << lucas(m + n, n) << "\n";
}
signed main()
{
int T;
std::cin >> T;
while (T--) solve();
return 0;
}
Lucas 二
#include<bits/stdc++.h>
#define int long long
using namespace std;
int f[1000010], Inv[1000010], p;
int ksm(int a, int b)
{
int res = 1;
while (b) {
if (b & 1) {res = res * a % p;}
a = a * a % p;
b >>= 1;
}return res;
}
int binom(int a, int b)
{
if (b < 0 || b > a) return 0;
return f[a] * Inv[b] % p * Inv[a - b] % p;
}
void solve()
{
int n, m;
cin >> n >> m;
int ans = 1;
while (n > 0 || m > 0) {
ans = ans * binom(n % p, m % p) % p;
n /= p, m /= p;
}
cout << ans << "\n";
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T;
cin >> p >> T;
f[0] = f[1] = 1;
for (int i = 2; i <= p; i++) {
f[i] = f[i - 1] * i % p;
}
Inv[p - 1] = ksm(f[p - 1], p - 2);
for (int i = p - 1; i >= 1; i--) Inv[i - 1] = Inv[i] * i % p;
while (T--) solve();
return 0;
}
中国剩余定理
#include<bits/stdc++.h>
#define i64 long long
int main()
{
int n;
std::cin >> n ;
std::vector<i64>a(n + 2), b(n + 2);
for (int i = 1; i <= n; i++) {
std::cin >> a[i] >> b[i];
}
std::function<i64(i64, i64, i64 &, i64 &)>exgcd = [&](i64 a, i64 b, i64 &x, i64 &y) {
if (b == 0) {
x = 1, y = 0; return a;
}
i64 pa = exgcd(b, a % b, y, x);
y -= (a / b) * x;
return pa;
};
std::function<i64(i64, i64)> inv = [&](i64 a, i64 p) {
i64 x, y;
exgcd(a, p, x, y);
return (x + p) % p;
};
std::function<i64()>CRT = [&]{
i64 p = 1, res = 0;
for (int i = 1; i <= n; i++) p *= a[i];
for (int i = 1; i <= n; i++) {
i64 pa = p / a[i];
res += (b[i] * pa * inv(pa, a[i])) % p;
}return res % p;
};
std::cout << CRT();
return 0;
}
FFT 递归
#include<bits/stdc++.h>
typedef std::complex<double> comp;
const int M = 1e6+10;
const comp I(0, 1);
const double PI = acos(-1);
comp A[M * 3], B[M * 3], tmp[M * 3], ans[M * 3];
void fft(comp F[], int N, int sgn = 1)
{
if (N == 1) return;
memcpy(tmp, F, sizeof (comp) * N);
for (int i = 0; i < N; i++) {
if (i & 1) F[i / 2 + N / 2] = tmp[i];
else F[i / 2] = tmp[i];
}
fft(F, N / 2, sgn), fft(F + N / 2, N / 2, sgn);
comp *G = F, *H = F + N / 2;
comp cur = 1, step = exp(2 * PI / N * sgn * I);
for (int k = 0; k < N / 2; k++) {
tmp[k] = G[k] + cur * H[k];
tmp[k + N / 2] = G[k] - cur * H[k];
cur *= step;
}
memcpy(F, tmp, sizeof (comp) * N);
}
int main()
{
int n, m, N;
std::cin >> n >> m;
N = 1 << std::__lg(n + m + 1) + 1;
for (int i = 0; i <= n; i++) std::cin >> A[i];
for (int i = 0; i <= m; i++) std::cin >> B[i];
fft(A, N), fft(B, N);
for (int i = 0; i < N; i++) {ans[i] = A[i] * B[i];}
fft(ans, N, -1);
for (int i = 0; i <= n + m; i++) {
std::cout << int(ans[i].real() / N + 0.1) << ' ' ;
}
return 0;
}
FFT 蝴蝶变化优化
#include<bits/stdc++.h>
typedef std::complex<double> comp;
const int M = 1e6+10;
const comp I(0, 1);
const double PI = acos(-1);
double A[M * 3], B[M * 3];
int rev[M * 3];
comp F[M * 3];
void fft(comp F[], int N, int sgn = 1)
{
for (int i = 0; i < N; i++) {
if (i < rev[i]) swap(F[i], F[rev[i]]);
}
for (int l = 1; l < N; l <<= 1) {
comp step = comp(cos(PI / l), sgn * sin(PI / l));
for (int i = 0; i < N; i += l * 2) {
comp cur(1, 0);
for (int k = i; k < i + l; k++) {
comp g = F[k], h = F[k + l] * cur;
F[k] = g + h, F[k + l] = g - h;
cur *= step;
}
}
}
}
int main()
{
int n, m, N;
std::cin >> n >> m;
N = 1 << std::__lg(n + m + 1) + 1;
int bit = std::__lg(N);
for (int i = 0; i < N; i++) {
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));
}
for (int i = 0; i <= n; i++) std::cin >> A[i];
for (int i = 0; i <= m; i++) std::cin >> B[i];
for (int i = 0; i <= std::max(n, m); i++) {
F[i] = comp(A[i], B[i]);
}
fft(F, N);
for (int i = 0; i < N; i++) {
F[i] = F[i] * F[i];
}
fft(F, N, -1);
for (int i = 0; i <= n + m; i++) {
std::cout << int(F[i].imag() / (N * 2) + 0.1) << ' ' ;
}
return 0;
}
NTT 优化的FFT
#include<bits/stdc++.h>
#define int long long
const int M = 1e6+10, P = 998244353, G = 3, Gi = 332748118;
int A[M * 3], B[M * 3], F[M * 3];
int rev[M * 3];
int ksm(int a, int b)
{
int res = 1;
while (b) {
if (b & 1) res = res * a % P;
a = a * a % P;
b >>= 1;
}return res;
}
void ntt(int F[], int N, int sgn = 1)
{
for (int i = 0; i < N; i++) {
if (i < rev[i]) std::swap(F[i], F[rev[i]]);
}
for (int l = 1; l < N; l <<= 1) {
int step = ksm(sgn == 1 ? G : Gi, (P - 1) / (l << 1));
for (int i = 0; i < N; i += l * 2) {
int cur = 1;
for (int k = i; k < i + l; k++) {
int g = F[k], h = F[k + l] * cur % P;
F[k] = (g + h) % P, F[k + l] = (g - h + P) % P;
cur = cur * step % P;
}
}
}
}
signed main()
{
int n, m, N;
std::cin >> n >> m;
N = 1 << std::__lg(n + m + 1) + 1;
int bit = std::__lg(N);
for (int i = 0; i < N; i++) {
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));
}
for (int i = 0; i <= n; i++) std::cin >> A[i];
for (int i = 0; i <= m; i++) std::cin >> B[i];
ntt(A, N), ntt(B, N);
for (int i = 0; i < N; i++) {
F[i] = A[i] * B[i] % P;
}
ntt(F, N, -1);
int inv = ksm(N, P - 2);
for (int i = 0; i <= n + m; i++) {
std::cout << inv * F[i] % P << ' ' ;
}
return 0;
}
高精度
#include<bits/stdc++.h>
#define int long long
const int M = 1e6+10, P = 998244353, G = 3, Gi = 332748118;
int A[M * 3], B[M * 3], F[M * 3];
int rev[M * 3];
int ksm(int a, int b)
{
int res = 1;
while (b) {
if (b & 1) res = res * a % P;
a = a * a % P;
b >>= 1;
}return res;
}
void ntt(int F[], int N, int sgn = 1)
{
for (int i = 0; i < N; i++) {
if (i < rev[i]) std::swap(F[i], F[rev[i]]);
}
for (int l = 1; l < N; l <<= 1) {
int step = ksm(sgn == 1 ? G : Gi, (P - 1) / (l << 1));
for (int i = 0; i < N; i += l * 2) {
int cur = 1;
for (int k = i; k < i + l; k++) {
int g = F[k], h = F[k + l] * cur % P;
F[k] = (g + h) % P, F[k + l] = (g - h + P) % P;
cur = cur * step % P;
}
}
}
}
signed main()
{
int n, m, N;
std::string a, b;
std::cin >> a >> b;
n = a.length(), m = b.length();
for (int i = 0; i < n; i++) A[i] = a[n - i - 1] - '0';
for (int i = 0; i < m; i++) B[i] = b[m - 1 - i] - '0';
N = 1 << std::__lg(n + m + 1) + 1;
int bit = std::__lg(N);
for (int i = 0; i < N; i++) {
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));
}
ntt(A, N), ntt(B, N);
for (int i = 0; i < N; i++) {
F[i] = A[i] * B[i] % P;
}
ntt(F, N, -1);
int inv = ksm(N, P - 2);
std::vector<int> ans(N + 1);
for (int i = 0; i <= N; i++) {
ans[i] += (inv * F[i] % P);
ans[i + 1] += ans[i] / 10;
ans[i] %= 10;
}
int lim = N;
while (!ans[lim] && lim >= 1) lim--;
lim++;
while (--lim >= 0) std::cout << ans[lim];
return 0;
}
分治FFT
类比cdq分治
#include<bits/stdc++.h>
#define int long long
const int M = 1e5+10;
const int P = 998244353, G = 3;
int rev[M << 2], f[M << 2], g[M << 2], n, a[M << 2], b[M << 2];
void init(int bit)
{
int N = 1 << bit;
for (int i = 0; i < N; i++) {
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));
}
}
int ksm(int x, int y)
{
int res = 1;
while (y) {
if (y & 1) res = res * x % P;
x = x * x % P;
y >>= 1;
}return res;
}
const int Gi = 332748118;
void ntt(int *F, int N, int sgn = 1)
{
for (int i = 0; i < N; i++) {
if (i < rev[i]) std::swap(F[i], F[rev[i]]);
}
for (int l = 1; l < N; l <<= 1) {
int step = ksm(sgn == 1 ? G : Gi, (P - 1) / (l << 1));
for (int i = 0; i < N; i += (l << 1)) {
int cur = 1;
for (int k = i; k < l + i; k++, cur = cur * step % P) {
int g = F[k], h = F[k + l] * cur % P;
F[k] = (g + h) % P, F[k + l] = (g - h + P) % P;
}
}
}
}
void solve(int l, int r, int bit)
{
if (bit <= 0) return;
if (l >= n) return ;
int mid = (l + r) >> 1;
solve(l, mid, bit - 1);
init(bit);
memset(a + (r - l) / 2, 0, sizeof (int) * (r - l) / 2);
memcpy(a, f + l, (r - l) / 2 * sizeof (int));
memcpy(b, g, sizeof(int) * (r - l));
ntt(a, 1 << bit), ntt(b, 1 << bit);
for (int i = 0; i < r - l; i++) a[i] = a[i] * b[i] % P;
ntt(a, 1 << bit, -1);
int N = 1 << bit;
int inv = ksm(r - l, P - 2);
for (int i = 0; i < r - l; i++) a[i] = a[i] * inv % P;
for (int i = (r - l) / 2; i < (r - l); i++) {
f[i + l] = (f[i + l] + a[i]) % P;
}
solve(mid, r, bit - 1);
}
signed main()
{
std::cin >> n;
int N = 1, bit = 0;
while (N < n) N <<= 1, bit++;
for (int i = 1; i < n; i++) std::cin >> g[i];
f[0] = 1;
solve(0, N, bit);
for (int i = 0; i < n; i++) {
std::cout << (f[i] + P) % P << ' ' ;
}
return 0;
}
大数质因子分解
const int S = 8; // 随机算法判定次数,8~10 就够了
// 龟速乘
long long mult_mod(long long a, long long b, long long c) {
a %= c, b %= c;
long long ret = 0;
long long tmp = a;
while (b) {
if (b & 1) {
ret += tmp;
if (ret > c) ret -= c;
}
tmp <<= 1;
if (tmp > c) tmp -= c;
b >>= 1;
}
return ret;
}
// 快速幂
long long qow_mod(long long a, long long n, long long _mod) {
long long ret = 1;
long long temp = a % _mod;
while (n) {
if (n & 1) ret = mult_mod(ret, temp, _mod);
temp = mult_mod(temp, temp, _mod);
n >>= 1;
}
return ret;
}
// 是合数返回true,不一定是合数返回false
bool check(long long a, long long n, long long x, long long t) {
long long ret = qow_mod(a, x, n);
long long last = ret;
for (int i = 1; i <= t; i++) {
ret = mult_mod(ret, ret, n);
if (ret == 1 && last != 1 && last != n - 1) return true;
last = ret;
}
if (ret != 1) return true;
return false;
}
// 是素数返回true,不是返回false
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
bool Miller_Rabin(long long n) {
if (n < 2) return false;
if (n == 2) return true;
if ((n & 1) == 0) return false;
long long x = n - 1;
long long t = 0;
while ((x & 1) == 0) { x >>= 1; t++; }
for (int i = 0; i < S; i++) {
long long a = rng() % (n - 1) + 1;
if (check(a, n, x, t))
return false;
}
return true;
}
long long factor[100];// 存质因数
int tol; // 质因数的个数,0~tol-1
long long gcd(long long a, long long b) {
long long t;
while (b) {
t = a;
a = b;
b = t % b;
}
if (a >= 0) return a;
return -a;
}
long long pollard_rho(long long x, long long c) {
long long i = 1, k = 2;
long long x0 = rng() % (x - 1) + 1;
long long y = x0;
while (1) {
i++;
x0 = (mult_mod(x0, x0, x) + c) % x;
long long d = gcd(y - x0, x);
if (d != 1 && d != x) return d;
if (y == x0) return x;
if (i == k) { y = x0; k += k; }
}
}
// 对n质因数分解,存入factor,k一般设置为107左右
void findfac(long long n, int k) {
if (n == 1) return;
if (Miller_Rabin(n)) {
factor[tol++] = n;
return;
}
long long p = n;
int c = k;
while (p >= n) p = pollard_rho(p, c--);
findfac(p, k);
findfac(n / p, k);
}
vector<int> fac(long long n) {
tol = 0;
vector<int>ret;
findfac(n, 107);
for (int i = 0; i < tol; i++)ret.push_back(factor[i]);
return ret;
}