01Trie
const int N = 10000005;
int cnt = 1;
int son[N][2], n, a[N];
void Insert(int k) {
int now = 0;
for (int i = 1 << 30; i; i >>= 1) {
int ch = (k & i) ? 1 : 0;
if (!son[now][ch])
son[now][ch] = cnt++;
now = son[now][ch];
}
}
int Find(int k) {
int now = 0;
int maxn = 0;
for (int i = 1 << 30; i; i >>= 1) {
int ch = (k & i) ? 0 : 1;
if (son[now][ch]) {
maxn += i;
now = son[now][ch];
} else
now = son[now][!ch];
}
return maxn;
}
线段树式01Trie
const int N = 5e5 + 5;
int rt,ls[N * 30],rs[N * 30],sum[N * 30],cnt;
void push_up(int p) {
sum[p] = sum[ls[p]] + sum[rs[p]];
}
void ins(int &p,int x,int dep) {
if(!p) p = ++cnt;
if(dep == -1) {
sum[p]++;
return;
}
(x >> dep) & 1 ? ins(rs[p],x,dep - 1) : ins(ls[p],x,dep - 1);
push_up(p);
}
int Find(int &p,int x,int dep,...) {
if(!p) return 0;
if(dep == -1) return sum[p];
int res = 0;
if((x >> dep) & 1)
...,res += Find(rs[p],x,dep - 1,...);
else
...,res += Find(ls[p],x,dep - 1,...);
return res;
}
拉格朗日插值
这个在 N O I P NOIP NOIP 还是能排上用场的 – NOIP2022 微信步数
非常有趣的根据 n + 1 n + 1 n+1 个点确定 n n n 次函数
#include<bits/stdc++.h>
using namespace std;
#define int long long
int rd() {
int x = 0, w = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * w;
}
void wt(int x) {
static int sta[35];
int f = 1;
if(x < 0) f = -1,x *= f;
int top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
if(f == -1) putchar('-');
while (top) putchar(sta[--top] + 48);
}
const int N = 2e3+5,mod = 998244353;
int n,k,x[N],y[N];
int qpow(int x,int k) {
int res = 1;
while(k) {
if(k & 1) res = (res * x) % mod;
x = (x * x) % mod;
k >>= 1;
}
return res;
}
int inv[N][N];
signed main() {
n = rd(),k = rd();
for(int i = 1;i<=n;i++) x[i] = rd(),y[i] = rd();
int ans = 0;
for(int i = 1;i<=n;i++)
for(int j = 1;j<=n;j++)
if(i ^ j)
inv[i][j] = qpow(x[i] - x[j] + mod,mod - 2);
for(int i = 1;i<=n;i++) {
int res = 1;
for(int j = 1;j<=n;j++)
if(j ^ i)
res = (res * (k - x[j] + mod) % mod * inv[i][j]) % mod;
ans = (ans + res * y[i] % mod) % mod;
}
wt(ans);
return 0;
}
数位dp
const int N = 15;
int a,b;
int dp[N][N]; //dp[i][j] 第 i 位 数字是 k
void init(){
// 初始化
for(int i = 0;i <= 9;i++) dp[1][i] = 1;
for(int i = 2;i <= 13;i++) {
for(int j = 0;j<=9;j++) {
for(int k = 0;k<=j-2;k++) dp[i][j] += dp[i-1][k];
for(int k = j + 2;k<=9;k++) dp[i][j] += dp[i-1][k];
}
}
}
int solve(int x){
//解决问题
int d[N];
memset(d,0,sizeof(d));
int len = 0,ans = 0;
while(x) {d[++len] = x%10;x /= 10;}// 拆位
for(int i = 1;i<len;i++) for(int j = 1;j<=9;j++) ans += dp[i][j]; // 取位数小于该 x 的全集
// 接下来逼近 x
for(int i = 1;i<d[len];i++) ans += dp[len][i]; // 取最高位小于概述的全集
for(int i = len-1;i >= 1;i--) {
//从最高位往低位探究
for(int j = 0;j<=min(d[i+1]-2,d[i]-1);j++) ans += dp[i][j];
for(int j = d[i+1]+2;j<d[i];j++) ans += dp[i][j];
if(d[i] > d[i+1] - 2 && d[i] < d[i+1] + 2) break;
}
return ans;
}
instream : a ~ b
outstream : solve(b + 1) - solve(a);
// solve(x) 的计算是左闭右开的
ola质数筛
bool vis[N];
int p[N],top;
void init() {
vis[1] = true;
for(int i = 2;i<=1e5;i++) {
if(!vis[i])
p[++top] = i;
for(int j = 1;j<=top && p[j] * i <= 1e5;j++) {
vis[i * p[j]] = true;
if(i % p[j] == 0)
break;
}
}
}
轮廓线dp
使用的关键在于发现状态数并不多,用 n n n 进制数来表现轮廓的状态
d p dp dp 的 转移 和 轮廓线 息息相关
如图,蓝色轮廓线状态只能转移到含一个紫色的状态
因为 $ 1 \leq n,m \leq 10$ 用
11
11
11 进制压缩状态就可以了
轮廓线状态压缩:
ll zip(int *now){
ll res = 0;
for(int i = n;i>=1;i--) res = res * 11 + now[i];
return res;
}
void unzip(ll S,int *now) {
for(int i = 1;i<=n;i++) {
now[i] = S % 11;
S /= 11;
}
}
AC-Code:
#include<bits/stdc++.h>
using namespace std;
int rd() {
int x = 0, w = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * w;
}
void wt(int x) {
static int sta[35];
int f = 1;
if(x < 0) f = -1,x *= f;
int top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
if(f == -1) putchar('-');
while (top) putchar(sta[--top] + 48);
}
typedef long long ll;
int n,m;
int a[11][11],b[11][11];
unordered_map<ll,ll> dp;
ll zip(int *now){
ll res = 0;
for(int i = n;i>=1;i--) res = res * 11 + now[i];
return res;
}
void unzip(ll S,int *now) {
for(int i = 1;i<=n;i++) {
now[i] = S % 11;
S /= 11;
}
}
const ll inf = 1e9;
ll dfs(ll S){
if(dp.count(S)) return dp[S];
int size = 0;
int *now = new int[11];
unzip(S,now);
for(int i = 1;i<=n;i++) size += now[i];
int re = (size & 1) ? inf:-inf;
for(int i = 1;i<=n;i++) {
if((i == 1 && now[i] < m) || (i != 1 && now[i] < now[i-1])) {
now[i]++;
if((size & 1)) re = min((ll)re,dfs(zip(now)) - b[i][now[i]]);
else re = max((ll)re,dfs(zip(now)) + a[i][now[i]]);
now[i]--;
}
}
delete now;
return dp[S] = re;
}
signed main() {
n = rd(),m = rd();
for(int i = 1;i<=n;i++)
for(int j = 1;j<=m;j++)
a[i][j] = rd();
for(int i = 1;i<=n;i++)
for(int j = 1;j<=m;j++)
b[i][j] = rd();
ll ed = 0;
for(int i = 1;i<=n;i++) ed = ed * 11 + m;
dp[ed] = 0;
ll ans = dfs(0);
wt(ans);
return 0;
}
BKDR-Hash
AC-code:
#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)
#define ull unsigned long long
const int N = 1e5+6;
ull base[4] = {4969,71011,4339,131};
char s[N];
ull BKDRhash(char *s,int k) {
ull H = 0;
while(*s) H = H * base[k] + (*s++);
return H;
}
ull bn[4][N];
int n;
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cin>>n;
For(i,1,n) {
cin>>s;
For(j,3,3)
bn[j][i] = BKDRhash(s,j);
}
int ans = 0;
For(j,3,3) sort(bn[j]+1,bn[j] + n + 1);
For(i,1,n) {
bool check = true;
For(j,3,3) if(bn[j][i] == bn[j][i + 1]){check = false;break;}
if(check)ans++;
}
cout<<ans;
return 0;
}
路径压缩并查集
code:
const int N = 1005;
int s[N<<1];
int find(int x) {
if(s[x] ^ x) s[x] = find(s[x]);
return s[x];
}
void merge(int x,int y) {
int fx = find(x),fy = find(y);
s[fy] = fx;
}
Floyd
code:
#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)
const int N = 105,INF = 1e9;
int dp[N][N],n,m,u,v,w;
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cin>>n>>m;
memset(dp,0x3f,sizeof(dp));
For(i,1,m) {
cin>>u>>v>>w;
dp[u][v] = dp[v][u] = min(dp[u][v],w);
}
//floyd
For(k,1,n) {
For(i,1,n) {
For(j,1,n) {
dp[i][j] = min(dp[i][j],dp[i][k] + dp[j][k]);
}
}
}
return 0;
}
ST表
code:
#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)
#define LOG2(x) __lg(x)
const int N = 1e5 + 10;
int n, m, a[N], x, y, dp[N][25];
void st_init() {
For(i, 1, n) dp[i][0] = a[i];
int p = LOG2(n);
For(k, 1, p) {
for (int s = 1; s + (1 << k) <= n + 1; s++) {
dp[s][k] = max(dp[s][k - 1], dp[s + (1 << (k - 1))][k - 1]);
}
}
}
int query(int L, int R) {
int k = LOG2(R - L + 1);
return max(dp[L][k], dp[R - (1 << k) + 1][k]);
}
signed main() {
cin >> n >> m;
For(i, 1, n) cin >> a[i];
st_init();
For(i, 1, m) {
cin >> x >> y;
cout << query(x, y) << '\n';
}
return 0;
}
Spfa
code:
int dis[N],Neg[N];
bool inq[N];
vector<Edge> edge[N];
il bool spfa(int s) {
For(i,0,N-1) Neg[i] = 0;
Neg[s] = 1;
dis[s] = 0;
queue<int> q;
q.push(s);
inq[s] = true;
while(!q.empty()) {
int t = q.front();
q.pop();
inq[t] = false;
for(auto i:edge[t]) {
if(dis[t] + i.w < dis[i.to]) {
dis[i.to] = dis[t] + i.w;
if(!inq[i.to]) {
inq[i.to] = true;
q.push(i.to);
Neg[i.to]++;
if(Neg[i.to] > n) return 1;
}
}
}
}
return 0;
}
Ola路径
code:
#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)
#define CIN const int
#define il inline
CIN N = 2e5 + 10;;
int n,m,f,t,posa = 1,del[N],st[N],top;
vector<int> g[N];
int dg[N],A,B;
il void dfs(int u) {
for(int i = del[u];i < g[u].size();i = del[u]) {
del[u]++;
dfs(g[u][i]);
}
st[++top] = u;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cin>>n>>m;
For(i,1,m) {
cin>>f>>t;
g[f].push_back(t);
dg[t]--;
dg[f]++;
}
For(i,1,n) sort(g[i].begin(),g[i].end());
For(i,1,n) {
if(dg[i] == 1) A++,posa = i;
if(dg[i] == -1) B++;
if(A > 1||B > 1) cout<<"No",exit(0);
if(dg[i] > 1|| dg[i] < -1) cout<<"No",exit(0);
}
if(A != B) cout<<"No",exit(0);
dfs(posa);
for(int i = top;i>=1;i--) cout<<st[i]<<' ';
return 0;
}
差分约束
code:
#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)
const int N = 5005,INF = INT_MAX;
struct Edge{
int to,w;
Edge(int t,int w) :to(t),w(w) {}
};
int m,n,u,v,w;
int dis[N],Neg[N];
bool inq[N];
vector<Edge> edge[N];
void clear() {
For(i,0,N-1) edge[i].clear();
For(i,0,N-1) dis[i] = INF,inq[i] = false;
m = 0,n = 0,u = 0,v = 0,w = 0;
}
bool spfa(int s) {
For(i,0,N-1) Neg[i] = 0;
Neg[s] = 1;
dis[s] = 0;
deque<int> q;//SLF
q.push_back(s);
inq[s] = true;
while(!q.empty()) {
int t = q.front();
q.pop_front();
inq[t] = false;
for(auto i:edge[t]) {
if(dis[t] + i.w < dis[i.to]) {
dis[i.to] = dis[t] + i.w;
if(!inq[i.to]) {
inq[i.to] = true;
if(!q.empty()&&dis[i.to] >= dis[q.front()])q.push_back(i.to);
else q.push_back(i.to);
Neg[i.to]++;
if(Neg[i.to] > n) return 1;
}
}
}
}
return 0;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
clear();
cin>>n>>m;
For(i,1,m){
cin>>v>>u>>w;
edge[u].push_back(Edge(v,w));
}
For(i,1,n) edge[0].push_back(Edge(i,0));
if(spfa(0)) {
cout<<"NO\n";
}
else For(i,1,n) cout<<dis[i]+5<<' ';
return 0;
}
传递闭包
code:
#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)
const int N = 105;
int n,a[N][N];
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cin>>n;
For(u,1,n) {
For(i,1,n) {
cin>>a[u][i];
}
}
For(k,1,n) {
For(i,1,n) {
For(j,1,n) {
a[i][j] |= a[i][k] & a[k][j];
}
}
}
For(i,1,n) {
For(j,1,n) {
cout<<a[i][j] <<' ';
}
cout<<'\n';
}
return 0;
}
模意义下乘法逆元
inv!递推法
code:
#include <bits/stdc++.h>
using namespace std;
#define CIN const int
#define il inline
#define LOG2(x) __lg(x)
#define MJY(p) freopen(p".in","r",stdin);freopen(p".out","w",stdout);
#define int long long
CIN N = 3e6+5;
int inv[N],n,p;
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
// clock_t start,end;
// start = clock();
cin>>n>>p;
inv[1] = 1;
for(int i = 2;i<=n;i++) {
inv[i] = (p - p / i) * inv[p % i] % p;
}
for(int i = 1;i<=n;i++) {
cout<<inv[i]<<'\n';
}
// end = clock();
// cout<<"time = "<<double(end-start)/CLOCKS_PER_SEC<<"s"<<endl;
return 0;
}
exgcd 求法
code:
#include <bits/stdc++.h>
using namespace std;
#define CIN const int
#define il inline
#define LOG2(x) __lg(x)
#define MJY(p) freopen(p".in","r",stdin);freopen(p".out","w",stdout);
#define int long long
void exgcd(int a,int b,int &x,int &y) {
if(!b) {
x = 1;
y = 0;
}else {
exgcd(b,a % b,x,y);
int t = x;
x = y;
y = t - a/b * y;
}
}
int mod_inv(int a,int p) {
int x,y;
exgcd(a,p,x,y);
x = (x % p + p) % p;
return x;
}
CIN N = 3e6+5;
int n,p,f[N],inv[N];
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
// clock_t start,end;
// start = clock();
cin>>n>>p;
f[0] = f[1] = 1;
for(int i = 2;i<=n;i++) f[i] = f[i-1] * i % p;
inv[n] = mod_inv(f[n],p);
for(int i = n-1;i>=1;i--) inv[i] = inv[i + 1] * (i + 1) % p;
for(int i = 1;i<=n;i++) cout<<inv[i] * f[i-1] % p<<'\n';
// end = clock();
// cout<<"time = "<<double(end-start)/CLOCKS_PER_SEC<<"s"<<endl;
return 0;
}
费马小定理法
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = ?;
int qpow(int x,int k) {
int r = 1;
while(k) {
if(k & 1) r = r * x % mod;
x = (x * x) % mod;
k >>= 1;
}
return r;
}
signed main() {
int x = rd();
wt(qpow(x,mod - 1));
}
lucas 定理
code:
const int N = ?;
int fac[N],p;
int qpow(int x,int k) {
int res = 1;
while(k) {
if(k & 1) res = (res * x) % p;
x = (x * x) % p;
k >>= 1;
}
return res;
}
int C(int a,int b) {
if(b > a) return 0;
return ((fac[a] * qpow(fac[b],p-2)) % p * qpow(fac[a - b],p-2) % p);
}
int lucas(int a,int b) {
if(!b) return 1;
return C(a % p,b % p) * lucas(a / p,b / p) % p;
}
signed main(){
fac[0] = fac[1] = 1;
for(int i = 2;i<N;i++) fac[i] = fac[i-1] * i % p;
return 0;
}
拓扑排序
#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)
int n,t,deg[105];
vector<int> son[105];
queue<int> q;
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cin>>n;
For(i,1,n) {
while(cin>>t) {
if(t^0) {
deg[t]++;
son[i].push_back(t);
}else goto EXIT;
}
EXIT:;
}
For(i,1,n) {
if(deg[i] == 0) {
cout<<i<<' ';
q.push(i);
}
}
while(!q.empty()){
int x = q.front();
q.pop();
for(int k:son[x]){
deg[k]--;
if(!deg[k]) {
cout<<k<<' ';
q.push(k);
}
}
}
return 0;
}
LCA
树剖求法
code:
#include<bits/stdc++.h>
using namespace std;
int rd() {
int x = 0, w = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * w;
}
void wt(int x) {
static int sta[35];
int f = 1;
if(x < 0) f = -1,x *= f;
int top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
if(f == -1) putchar('-');
while (top) putchar(sta[--top] + 48);
}
const int N = 2e5+5;
int n;
int head[N],nxt[N<<1],to[N<<1],cnt;
void init() {memset(head,-1,sizeof(head));cnt = 0;}
void add(int u,int v) {
nxt[cnt] = head[u];
to[cnt] = v;
head[u] = cnt++;
}
int fa[N],son[N],siz[N],dep[N],top[N];
void dfs1(int x,int f) {
fa[x] = f;
siz[x] = 1;
dep[x] = dep[f] + 1;
for(int i = head[x];~i;i = nxt[i]) {
int y = to[i];
if(y ^ f) {
dfs1(y,x);
siz[x] += siz[y];
if(siz[son[x]] < siz[y]) son[x] = y;
}
}
}
void dfs2(int x,int topx) {
top[x] = topx;
if(!son[x]) return;
dfs2(son[x],topx);
for(int i = head[x];~i;i = nxt[i]) {
int y = to[i];
if(y ^ fa[x] && y ^ son[x]) dfs2(y,y);
}
}
int LCA(int x,int y) {
while(top[x] ^ top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x,y);
x = fa[top[x]];
}
return dep[x] < dep[y] ? x : y;
}
signed main() {
n = rd();
for(int i = 1;i<n;i++){
int u = rd(),v = rd();
add(u,v);add(v,u);
}
dfs1(1,0);dfs2(1,1);
int q = rd();
while(q--) {
int x = rd(),y = rd();
wt(LCA(x,y));
putchar('\n');
}
return 0;
}
倍增求LCA
#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)
const int N = 5e5+5;
struct node{
int t,n;
}edge[N<<1];
int head[N<<1],cnt;
void init(){
For(i,0,(N<<1)-1) edge[i].n = -1,head[i] = -1;
cnt = 0;
}
void addedge(int u,int v){
edge[cnt].t = v;edge[cnt].n = head[u];head[u] = cnt++;
}
int fa[N][20],deep[N];
void dfs(int x,int f) {
deep[x] = deep[f] + 1;
fa[x][0] = f;
for(int i = 1;(1<<i) <= deep[x];i++) fa[x][i] = fa[fa[x][i-1]][i-1];
for(int i = head[x];~i;i = edge[i].n) if(edge[i].t^f) dfs(edge[i].t,x);
}
int LCA(int x,int y) {
if(deep[x] < deep[y]) swap(x,y);
for(int i = 19;i >= 0;i--) if(deep[x] - (1<<i) >= deep[y]) x = fa[x][i];
if(x == y) return x;
for(int i = 19;i>=0;i--) if(fa[x][i]^fa[y][i]) x = fa[x][i],y = fa[y][i];
return fa[x][0];
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
init();
int n,m,root;
cin>>n>>m>>root;
For(i,1,n-1) {
int u,v;
cin>>u>>v;
addedge(u,v);
addedge(v,u);
}
dfs(root,0);
while(m--) {
int a,b;
cin>>a>>b;
cout<<LCA(a,b)<<"\n";
}
return 0;
}
DFS序求LCA
#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)
#define LOG2(x) __lg(x)
const int N = 5e5+5;
int n,m,s,dfn,num[N],dp[19][N];
vector<int> e[N];
int get(int x,int y) {
return num[x] < num[y] ? x : y;
}
void dfs(int id,int fa) {
dp[0][num[id] = ++dfn] = fa;
for(int i:e[id]) {
if(i^fa) dfs(i,id);
}
}
int lca(int u,int v) {
if(u == v) return u;
if((u = num[u]) > (v = num[v])) swap(u,v);
int d = LOG2(v - u++);
return get(dp[d][u],dp[d][v - (1<<d) + 1]);
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cin>>n>>m>>s;
for(int i = 2,u,v;i <= n;i++) {
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs(s,0);
For(i,1,LOG2(n))
for(int j = 1;j + (1<<i) -1 <= n;j++)
dp[i][j] = get(dp[i-1][j],dp[i-1][j + (1<<i-1)]);
For(i,1,m) {
int u,v;
cin>>u>>v;
cout<<lca(u,v)<<'\n';
}
return 0;
}