ACM模板

ACM模板 ——————by ALizen

0.模板

#include <bits/stdc++.h>
#define ll long long
#define pf(x) cout<<"("<<__LINE__<<")"<<#x<<" ="<<x<<endl
using namespace std;
void scan(__int128 &x)//输入
{
    x = 0;
    int f = 1;
    char ch;
    if((ch = getchar()) == '-') f = -f;
    else x = x*10 + ch-'0';
    while((ch = getchar()) >= '0' && ch <= '9')
        x = x*10 + ch-'0';
    x *= f;
}
void print(__int128 x)
{
    if(x < 0)
    {
        x = -x;
        putchar('-');
    }
     if(x > 9) print(x/10);
    putchar(x%10 + '0');
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    return 0;
}

1.数据结构

线段树

// 以加法线段树为模板
const int N = 1e5 + 10;
int w[N];
struct node {
    int l, r;
    ll val;
    ll lazy;
}t[N << 2];
void pushdown(node& op, ll lazy) {
    op.val += lazy * (op.r - op.l + 1);
    op.lazy += lazy;
}
void pushdown(int x) {
    if (!t[x].lazy) return;
    pushdown(t[x << 1], t[x].lazy);
	pushdown(t[x << 1 | 1], t[x].lazy);
    t[x].lazy = 0;
}
void pushup(int x) {
    t[x].val = t[x << 1].val + t[x << 1 | 1].val;
}
void build(int l, int r, int x = 1) {
    t[x] = { l, r, w[l], 0 };
    if (l == r) return;
    int mid = l + r >> 1;
    build(l, mid, x << 1), build(mid + 1, r, x << 1 | 1);
    pushup(x);
}
void modify(int l, int r, int c, int x = 1) {
    if (l <= t[x].l && r >= t[x].r) { pushdown(t[x], c); return; }
    pushdown(x);
    int mid = t[x].l + t[x].r >> 1;
    if (l <= mid) modify(l, r, c, x << 1);
    if (r > mid) modify(l, r, c, x << 1 | 1);
    pushup(x);
}
ll query(int l, int r, int x = 1) {
    if (l <= t[x].l && r >= t[x].r) return t[x].val;
    pushdown(x);
    int mid = t[x].l + t[x].r >> 1;
    ll res = 0;
    if (l <= mid) res += query(l, r, x << 1);
    if (r > mid) res += query(l, r, x << 1 | 1);
    return res;
}

线段树后续

1)多tag效应
struct node{
    int l, r;
    ll sum1, sum2, sum3;
    ll add, mul, lazy; 
}t[N << 2]; 
int n,m;
void pushup(int x){
	node &p = t[x];
	node &l = t[x << 1];
	node &r = t[x << 1 | 1];
	
	p.sum1 = (l.sum1 + r.sum1) % mod;
	p.sum2 = (l.sum2 + r.sum2) % mod;
	p.sum3 = (l.sum3 + r.sum3) % mod;
}
void pushdown(node &op, ll add, ll mul,ll lazy){
	ll len = op.r - op.l + 1;
    if (lazy) {
        lazy %= mod;
        op.sum1 = lazy * len % mod;
        op.sum2 = lazy * lazy % mod * len % mod;
        op.sum3 = lazy * lazy % mod * lazy % mod * len % mod;
        
        op.add = 0, op.mul = 1; op.lazy = lazy;
    }
    
    if (mul != 1) { 
        op.sum1 = op.sum1 * mul % mod;
        op.sum2 = op.sum2 * mul % mod * mul % mod;
        op.sum3 = op.sum3 * mul % mod * mul % mod * mul % mod;
        
        op.add = mul * op.add % mod;
        op.mul = op.mul * mul % mod;
    }

    if (add) {
        op.sum3 = (op.sum3 + len * add % mod * add % mod * add % mod + 3 * op.sum2 % mod * add % mod + 3 * op.sum1 % mod * add % mod * add % mod) % mod;
        op.sum2 = (op.sum2 + 2 * add % mod * op.sum1 % mod + len * add % mod * add % mod) % mod;
        op.sum1 = (op.sum1 + len * add % mod) % mod;
        
        op.add = (op.add + add) % mod;
    }
}

void pushdown(int x) {
    node& p = t[x];
    pushdown(t[x << 1], p.add, p.mul, p.lazy);
    pushdown(t[x << 1 | 1], p.add, p.mul, p.lazy);
    p.add = 0, p.mul = 1, p.lazy = 0;
}

void build(int l, int r, int x = 1){
	t[x] = {l, r, 0, 0, 0, 0, 1, 0};
	if(l == r)return ;
	
	int mid = l + r >> 1;
	build(l, mid, x << 1);
	build(mid + 1, r, x << 1 | 1);
	pushup(x);
}

void modify(int l,int r,int id, int c,int x = 1){
	if(l <= t[x].l && r >= t[x].r){
		if(id == 1) pushdown(t[x],c,1,0);
		if(id == 2) pushdown(t[x],0,c,0);
		if(id == 3) pushdown(t[x],0,1,c);
		return ;
	}
	
	pushdown(x);
	int mid = t[x].l + t[x].r >> 1;
	if(l <= mid) modify(l,r,id,c,x << 1);
	if(r > mid) modify(l,r,id,c,x << 1 | 1);
	pushup(x);
}
int query(int l,int r,int id,int x = 1){
	if(l <=t[x].l && r >= t[x].r){
		if(id == 1) return t[x].sum1;
		if(id == 2) return t[x].sum2;
		if(id == 3) return t[x].sum3;
	}
	
	pushdown(x);
	int mid = t[x].l + t[x].r >> 1;
	int res = 0;
	if(l <= mid) res = (res + query(l,r,id,x<< 1));
	if(r > mid) res = (res + query(l,r,id,x<< 1 | 1));
	return res  % mod;
}
2)合并操作
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef long long ll;

inline void rd();
inline void ot();
inline void debug();

const int INF = 0x3f3f3f3f;
const int N = 2e5+7;
struct node{
	int l,r;
	int sum[3];
}t[N << 2];

char s[N];
node operator + (const node& A,const node& B){
	node res;
	res.l = A.l;
	res.r = B.r;
	res.sum[0] = A.sum[0]+B.sum[A.sum[0]%3];
	res.sum[1] = A.sum[1]+B.sum[(1+A.sum[1])%3];
	res.sum[2] = A.sum[2]+B.sum[(2+A.sum[2])%3];
	return res;
}
void pushup(int x){
	t[x].sum[0] = t[x << 1].sum[0] + t[x << 1|1].sum[t[x << 1].sum[0] % 3];
	t[x].sum[1] = t[x << 1].sum[1] + t[x << 1|1].sum[(1+t[x << 1].sum[1]) % 3];
	t[x].sum[2] = t[x << 1].sum[2] + t[x << 1|1].sum[(2+t[x << 1].sum[2] )% 3];
}
void build(int l,int r,int x = 1){
	t[x].l = l;
	t[x].r = r;
	if(l == r){
		if(s[l] == 'W') t[x].sum[0] = t[x].sum[1] = t[x].sum[2] = 1;
		else if(s[l] == 'D') t[x].sum[0] = t[x].sum[1] = t[x].sum[2] = 0;
		else t[x].sum[0] =0, t[x].sum[1] = t[x].sum[2] = -1;
		return ;
	}
	int mid = l + r >> 1;
	build(l,mid,x<<1);
	build(mid+1,r,x<<1|1);
	pushup(x);
}
node query(int l,int r,int x = 1){
	if(l <= t[x].l && t[x].r <= r) return t[x];
	int mid = t[x].l + t[x].r >> 1;
	if(l > mid) return query(l,r,x << 1|1) ;
	else if(r <= mid) return query(l,r, x<< 1);
	else return query(l,mid, x << 1) + query(mid+1,r,x<< 1|1);
}
void HHU_zyh(){
	int n,t;
	cin >> n >> t;
	cin >> s+1;
	build(1,n);
	while(t--){
		int l,r,s;
		cin >> l >> r >> s;
		node res = query(l,r);
		cout << s + res.sum[s%3] << endl;
	}
}
3)权值线段树
#include <bits/stdc++.h>
#define ll long long
#define pf(x) cout<<"("<<__LINE__<<")"<<#x<<"="<<x<<endl
using namespace std;
int n,k;
const int N = 1e5+7;
const int M = 1e6+7; 
struct node{
	int l,r;
	int v;
	ll sum;
}t[M<<2];
int w[N];
void build(int l,int r,int x = 1){
	t[x].l = l,t[x].r = r;
	if(l == r) return ;
	int mid = l + r >> 1;
    build(l, mid, x << 1), build(mid + 1, r, x << 1 | 1);
}
void pushup(int x){
	t[x].sum = t[x<<1].sum + t[x<<1|1].sum;
	t[x].v = t[x<<1].v + t[x<<1|1].v;
}

void modify(int pos,int v,int x = 1){
	if(t[x].l == t[x].r) {
		t[x].v += v;
		t[x].sum += pos * v;
		return;
	}
	int mid = (t[x].l + t[x].r) >> 1;
	if(pos <= mid) modify(pos,v,x<<1);
	else modify(pos,v,x<<1|1);
	pushup(x);
}
int query_kth(int k,int x = 1){
	if(t[x].l == t[x].r) return t[x].l;
	if(k <= t[x<<1].v) return query_kth(k,x<<1);
	else return query_kth(k-t[x<<1].v,x<<1|1);
}
int get_num(int l,int r,int x = 1){
	if(l <= t[x].l && t[x].r <= r) return t[x].v;
	int ans = 0;
	int mid = (t[x].l + t[x].r) >> 1;
	if(l <= mid) ans += get_num(l,r,x<<1);
	if(r > mid )ans += get_num(l,r,x<<1|1);
	return ans;
}
ll get_sum(int l,int r,int x = 1){
	if(l <= t[x].l && t[x].r <= r) return t[x].sum;
	ll ans = 0;
	int mid = (t[x].l + t[x].r) >> 1;
	if(l <= mid) ans += get_sum(l,r,x<<1);
	if(r > mid) ans += get_sum(l,r,x<<1|1);
	return ans;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> k;
    int mx = -1;
    for(int i = 1;i<=n;i++) {
    	cin >> w[i];
    	mx = max(w[i],mx);
	}
	build(0,mx);
	//pf(mx);
    for(int i = 1;i<k;i++) modify(w[i],1);
    ll ans = 1e15;
    for(int i = k;i<=n;i++){
    	modify(w[i],1);
    	int mid = query_kth(k/2+1);
    	//pf(mid);
    	ll pre_num = get_num(0,mid);
    	//pf(pre_num);
    	ll aft_num = get_num(mid,mx);
    	//pf(aft_num);
    	ll res = mid * pre_num - get_sum(0,mid) + get_sum(mid,mx) - mid * aft_num;
    	ans = min(ans,res);
    	modify(w[i-k+1],-1);
	}
	cout << ans;

    return 0;
}

4)主席树
int lch[N<<5],rch[N<<5];
int a[N],b[N];
int n,m;
int root[N<<5],tot;
int sum[N<<5]; 
int num;
void modify(int &rt,int old,int l,int r,int x){
	rt = ++ tot;
	lch[rt] = lch[old];
	rch[rt] = rch[old];
	sum[rt] = sum[old] + 1;
	if(l == r) return;
	int mid = l + r >> 1;
	if(x <= mid) modify(lch[rt],lch[rt],l,mid,x);
	else modify(rch[rt],rch[rt],mid+1,r,x);
}
int query(int u,int v,int l,int r,int k){
	if(l == r) return l;
	int x = sum[lch[v]] - sum[lch[u]];
	int mid = l + r >> 1;
	if(x >= k) return query(lch[u],lch[v],l,mid,k);
	else return query(rch[u],rch[v],mid+1,r,k-x);
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
    cin >> n >> m; 
    for(int i = 1; i <= n; i++){
    	cin >> a[i];
    	b[i] = a[i];
	}
	sort(b+1,b+1+n);
    num = unique(b+1,b+1+n) - (b+1);
    
    for(int i = 1; i <= n; i++){
    	int pos = lower_bound(b+1,b+1+num,a[i]) - b;
    	modify(root[i],root[i-1],1,num,pos);
	}
	while(m--){
		int l,r,k;
		cin >> l >> r >> k;
		cout << b[query(root[l-1],root[r],1,num,k)] <<'\n';
	}
    return 0;
}

左偏树

#include <bits/stdc++.h>
#define ll long long
#define pf(x) cout<<"("<<__LINE__<<")"<<#x<<"="<<x<<endl
using namespace std;
const int N = 1e6+7;
int l[N],r[N],val[N],p[N]; 
int dist[N];
int book[N];
int n,m;
int find(int x){
	if(p[x] != x) p[x] = find(p[x]);
	return p[x];
}
int merge(int x,int y){
	if(!x || !y) return x+y;
	if(val[x] > val[y]) swap(x,y);
	r[x] = merge(r[x],y);
	p[r[x]] = x;
	if(dist[r[x]] > dist[l[x]]) swap(l[x],r[x]);
	dist[x] = dist[r[x]] + 1;
	return x;
}
void solve(){
	char op;
	cin >> op;
	if(op == 'M') {
		int u,v;
		cin >> u >> v;
		if(book[u] || book[v]) return;
		int a = find(u);
		int b = find(v);
		if(a == b) return;
		int anc = merge(a,b);
		p[a] = p[b] = anc;	
	}
	else{
		int k;
		cin >> k;
		if(book[k]){
			cout <<"0\n";
			return;
		}
		int anc = find(k);
		book[anc] = 1;
		cout << val[anc] <<'\n';
		int fa = merge(l[anc],r[anc]);
		p[anc] = fa;
		p[fa] = fa;	
	}
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n;
    for(int i = 1; i<=n; i++){
    	cin >> val[i];
    	p[i] = i;
	}
    dist[0] = -1;
	cin >> m;
	while(m--) solve();

    return 0;
}

并查集

int n,m;
const int N=1e6+7; 
int p[N],s[N];
void init(){
	for(int i=1;i<=n;i++){
		p[i]=i;
		cin>>s[i];
	}
}
int find(int x){
	if(p[x]!=x){
		s[x]=max(s[x],s[p[x]]);
		p[x]=find(p[x]);
	}	
	return p[x];
}
int main(){
    cin>>n>>m;
    init();
    while(m--){
    	int a,b;
        cin>>a>>b;
    	int u=find(a),v=find(b);
    	if(u!=v){
    		p[u]=v;
    		s[v]=max(s[u],s[v]);
		}
	}
	LL sum=0;
    for(int i=1;i<=n;i++){
    	sum+=s[find(i)];
	}
    cout<<sum<<endl;
    return 0;
}

树状数组

1)区间修改,单点查询
void add(int p, int x){ //这个函数用来在树状数组中直接修改
    while(p <= n) sum[p] += x, p += p & -p;
}
void range_add(int l, int r, int x){ //给区间[l, r]加上x
    add(l, x), add(r + 1, -x);
}
int ask(int p){ //单点查询
    int res = 0;
    while(p) res += sum[p], p -= p & -p;
    return res;
}

range_add(i,i,x)
2)单点修改,区间查询
int lowbit(int x){
	return x&-x;
} 
void add(int p,ll c){
	while(p <= n){
		a[p] += c;
		p += lowbit(p);
	}
}
void range_add(int l,int r,ll c){
	add(l,c),add(r+1,-c);
}
ll get_sum(int p){
	ll res = 0;
	while(p){
		res += a[p];
		p -= lowbit(p);
	}
	return res;
}

add(i,x)
3)区间修改,区间查询
int lowbit(int x){
	return x&-x;
} 
void add(ll p, ll x){
    for(int i = p; i <= n; i += i & -i)
        sum1[i] += x, sum2[i] += x * p;
}
void range_add(ll l, ll r, ll x){
    add(l, x), add(r + 1, -x);
}
ll ask(ll p){
    ll res = 0;
    for(int i = p; i; i -= i & -i)
        res += (p + 1) * sum1[i] - sum2[i];
    return res;
}
ll range_ask(ll l, ll r){
    return ask(r) - ask(l - 1);
}

range_add(i,i,x)
4)二维单点修改,区间查询
void add(int x, int y, ll z){ //将点(x, y)加上z
    int memo_y = y;
    while(x <= n){
        y = memo_y;
        while(y <= m)
            tree[x][y] += z, y += y & -y;
        x += x & -x;
    }
}
ll ask(int x, int y){//求左上角为(1,1)右下角为(x,y) 的矩阵和
    ll res = 0, memo_y = y;
    while(x){
        y = memo_y;
        while(y)
            res += tree[x][y], y -= y & -y;
        x -= x & -x;
    }
    return res;
}
5)二维区间修改,单点查询
void add(int x, int y, ll z){ 
    int memo_y = y;
    while(x <= n){
        y = memo_y;
        while(y <= m)
            tree[x][y] += z, y += y & -y;
        x += x & -x;
    }
}
void range_add(int xa, int ya, int xb, int yb, ll z){
    add(xa, ya, z);
    add(xa, yb + 1, -z);
    add(xb + 1, ya, -z);
    add(xb + 1, yb + 1, z);
}
ll ask(int x, int y){
    ll res = 0, memo_y = y;
    while(x){
        y = memo_y;
        while(y)
            res += tree[x][y], y -= y & -y;
        x -= x & -x;
    }
    return res;
}
6)二维区间修改,区间查询
ll t1[N][N], t2[N][N], t3[N][N], t4[N][N];
void add(ll x, ll y, ll z){
    for(int X = x; X <= n; X += X & -X)
        for(int Y = y; Y <= m; Y += Y & -Y){
            t1[X][Y] += z;
            t2[X][Y] += z * x;
            t3[X][Y] += z * y;
            t4[X][Y] += z * x * y;
        }
}
void range_add(ll xa, ll ya, ll xb, ll yb, ll z){ //(xa, ya) 到 (xb, yb) 的矩形
    add(xa, ya, z);
    add(xa, yb + 1, -z);
    add(xb + 1, ya, -z);
    add(xb + 1, yb + 1, z);
}
ll ask(ll x, ll y){
    ll res = 0;
    for(int i = x; i; i -= i & -i)
        for(int j = y; j; j -= j & -j)
            res += (x + 1) * (y + 1) * t1[i][j]
                - (y + 1) * t2[i][j]
                - (x + 1) * t3[i][j]
                + t4[i][j];
    return res;
}
ll range_ask(ll xa, ll ya, ll xb, ll yb){
    return ask(xb, yb) - ask(xb, ya - 1) - ask(xa - 1, yb) + ask(xa - 1, ya - 1);
}

分块

//动态求数组中小于c*c的元素
#include <bits/stdc++.h>
#define ll long long
#define pf(x) cout<<"("<<__LINE__<<")"<<#x<<"="<<x<<endl
using namespace std;
const int N = 500500;
vector<int> v[3000];
int block,sum;
int n;
int a[N];
int pos[N],tag[N];
void init(){
	cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
	block = sqrt(n);
	sum = n / block + (n%block==0?0:1);
	for(int i = 1;i<=n;i++){
		pos[i] = (i-1)/block+1;
		v[pos[i]].push_back(a[i]);
	}
	for(int i = 1;i<=sum;i++) sort(v[i].begin(),v[i].end());
}
void update(int x){
	v[pos[x]].clear();
	for(int i = (pos[x]-1)*block+1;i<=min(pos[x]*block,n);i++) v[pos[x]].push_back(a[i]);
	sort(v[pos[x]].begin(),v[pos[x]].end());
}
void modify(int l,int r,int x){
	for(int i = l;i<=min(r,pos[l]*block);i++) a[i] += x;
	update(l);
	if(pos[l] != pos[r]) {
		for(int i = (pos[r]-1)*block+1;i<=r;i++) a[i] +=x;
		update(r);
	}
	for(int i = pos[l]+1;i<=pos[r]-1;i++) tag[i]+=x; 
}
int query(int l,int r,int k){
	int res = 0;
	for(int i = l;i<=min(r,pos[l]*block);i++) if(a[i]+tag[pos[i]]<k) res++;
	if(pos[l] != pos[r]) for(int i = (pos[r]-1)*block+1;i<=r;i++) if(a[i]+tag[pos[i]]<k) res++;
	
	for(int i = pos[l]+1;i<=pos[r]-1;i++){
		int tmp = k - tag[i];
		res += lower_bound(v[i].begin(),v[i].end(),tmp) - v[i].begin();
	}
	return res;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    init();
    for(int _=1;_<=n;_++){
    	int op,l,r,c;
		cin >> op >> l >> r >> c;
		if(!op) modify(l,r,c);
		else cout << query(l,r,c*c)<<'\n';
	}

    return 0;
}

2.图论

求最短路

1)Dijkstra
const int N = 1e6 + 7;
const int INF = 0x3f3f3f3f;
int n, m;
vector<PII> edge[N];
int dist[N],book[N];
int dijkstra(){
	dist[1]=0;
	priority_queue<PII, vector<PII>,greater<PII>> pq;
	pq.push({0,1});
	while(pq.size()){
		PII tep = pq.top();
		pq.pop();
		int dis = tep.first, pos = tep.second;
		if(book[pos]) continue;
		book[pos] = 1;
		for(auto pr : edge[pos]){
			int w = pr.first;
			int v = pr.second;
			if(dist[v] > dis + w){
				dist[v] > dis + w;
				pq.push({dist[v],v});
			}
		}
	}
	if(dist[n] == INF) return -1;
	return dist[n];
}
int main(){
	scanf("%d%d",&n,&m);
	MEM(dist,INF);
	while(m--){
		int a,b,c; 
		scanf("%d%d%d",&a,&b,&c);
		edge[a].push_back({c,b});
	}
    int ans = dijkstra();
    pf(ans);
    return 0;
}

2)Spfa
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
int n,m;
vector<PII> edge[N];
int dist[N];
int book[N];
int spfa(){
	queue<int> q;
	for(int i=1; i<=n; i++){
		q.push(i);
		book[i] = 1;
	}
	while(q.size()){
		int t = q.front();
		q.pop();
		book[t] = 0;
		for(auto j : edge[t]){
			int pos;
			int distance;
			pos = j.first;
			distance = j.second;
			if(dist[pos] > dist[t] + distance){
				dist[pos] = dist[t] + distance;
				cnt[pos] = cnt[t] + 1;
				if(cnt[pos] >= n) return 1;
				if(!book[pos]){
					q.push(pos);
					book[pos] = 1;
				}
			}
		}
	} 
	return 0;
}
void MorningStar(){
    scanf("%d %d",&n,&m);
    while(m--){
    	int a,b,c;
    	scanf("%d %d %d",&a, &b, &c);
    	edge[a].push_back({b,c});
	}
    int ans;
    ans = spfa();
	if(ans) printf("Yes");
	else printf("No"); 
}

3)Bellmen-Ford
int n, m, k;
int dist[N], backup[N];
vector<PII> edge[N];
int bellman_ford(){
	memset(dist, INF, sizeof dist);
	dist[1] = 0;
	for(int kase = 0; kase < k; kase ++) {
		memcpy(backup, dist, sizeof dist);	
		for(int i = 1; i <= n; i++){
			for(auto j : edge[i]){
				int st,ed,distance;
				st = i;
				ed = j.first;
				distance = j.second;
				dist[ed] = min(backup[st] + distance, dist[ed]);
				
			}
		}
	}
	if(dist[n] >= INF / 2) return INF;
	return dist[n];
}
void Smokers(){
	scanf("%d %d %d",&n, &m, &k);
	while(m--){
		int a,b,w;
		scanf("%d%d%d",&a, &b, &w);
		edge[a].push_back({b,w});
	}
	int ans = bellman_ford();
	if(ans== INF) printf("impossible");
	else printf("%d",ans);
	
}
4)Floyd
int n, m, q;
int d[N][N];
void floyd(){
	for(int k = 1; k <= n; k ++ ){
		for(int i = 1; i <=n ;i++){
			for(int j = 1;j <=n; j++){
				d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
			}
		}
	}
}
void Smokers(){
    scanf("%d %d %d",&n,&m,&q);
    for(int i=1; i<=n; i++){
    	for(int j=1; j <= n; j++){
    		if(i == j) d[i][j] = 0;
			else d[i][j] = INF; 
		}
	}
    while(m--){
    	int a, b, c;
    	scanf("%d %d %d",&a, &b, &c);
    	d[a][b] = min(d[a][b], c);
	}
    floyd();
    while(q -- ){
    	int a, b;
    	scanf("%d %d",&a,&b);
    	if(d[a][b] == INF) printf("impossible");
    	else printf("%d",d[a][b]);
	}
}

欧拉回路

#include <bits/stdc++.h>
#define ll long long
#define pf(x) cout<<"("<<__LINE__<<")"<<#x<<"="<<x<<endl
using namespace std;

const int N = 100100, M = 400100;

int h[N],e[M],ne[M],idx;
int ans[N<<1],cnt;
bool used[M];
int din[N],dout[N];
int n,m,ver;

void add(int a,int b){
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

void dfs(int u){
    for(int &i = h[u]; ~i; ){
        if(used[i]){
            i = ne[i]; continue;
        }

        used[i] = 1;
        if(ver == 1) used[i^1] = 1;

        int t;
        if(ver == 1){
            t = i / 2 + 1;
            if(i & 1) t = -t; 
        }
        else t = i + 1;

        int j = e[i];
        i = ne[i];
        dfs(j);
        ans[++cnt] = t;
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> ver >> n >> m;
    memset(h,-1,sizeof h);

    for(int i = 1; i <= m; i ++){
        int a,b;
        cin >> a >> b;
        add(a,b);
        if(ver ==  1) add(b,a);
        din[b]++;dout[a]++;
    }
    if(ver == 1){
        for(int i = 1; i <= n; i ++){
            if(din[i] + dout[i] & 1){
                puts("NO"); return 0;
            }
        }
    }
    else{
        for(int i = 1; i <= n; i ++){
            if(din[i] != dout[i]){
                puts("NO"); return 0;
            }
        }
    }

    for(int i = 1; i <= n; i ++){
        if(~h[i]) {
            dfs(i);break;
        }
    }

    if(cnt < m){
        puts("NO");return 0;
    }

    cout <<"YES\n";
    for(int i = cnt; i >= 1; i --) cout << ans[i] <<" ";


    return 0;
}


二分图

匈牙利算法
vector<int> edge[N];
int book[N];//右边否有被匹配 
int match[N];//右边和左边哪个点联系 
bool find(int x){
	for(auto k : edge[x]){
		if(!book[k]){
			book[k] = 1;
			if(match[k] == 0 || find(match[k])){
				match[k] = x;
				return true;
			}
		}
	}
	return false;
}
void MorningStar(){
	int n1,n2,m;
	cin >> n1 >> n2 >> m;
	while(m--){
		int u,v;
		cin >> u >> v;
		edge[u].push_back(v);	
	}
	
	MEM(book,0);
	MEM(match,0);
	int res = 0;
	for(int i = 1;i <= n1; i ++){
		MEM(book,0);
		if(find(i)) res++;
	}
	cout << res << '\n';
}

图的最小割

int n,m;
ll res;
int v[N];
int book[N];
ll dist[N];
ll g[N][N];
void Mincut(int n){
	for(int i = 0;i<n;i++) v[i] = i;
	while(n>1){
		int maxj = 1;
		int pre = 0;
		
	    for(int i=1; i<n; ++i)
        {
            dist[v[i]]=g[v[0]][v[i]];
            if(dist[v[i]]>dist[v[maxj]]) maxj=i;
        }
	    MEM(book,0);
	    book[v[0]] = 1;
	    
	    for(int i =1;i<n;i++){
	    	if(i == n-1){
	    		res = min(res,dist[v[maxj]]);
				for(int k = 0;k<n;k++){
					g[v[k]][v[pre]] = (g[v[pre]][v[k]] += g[v[maxj]][v[k]]);
				} 
				v[maxj] = v[--n];
			}
			book[v[maxj]] = 1;
			pre = maxj;
			maxj = -1;
			
			for(int j =1 ;j<n;j++){
				if(!book[v[j]]){
					dist[v[j]] += g[v[pre]][v[j]];
					if(maxj == -1 || (dist[v[j]] > dist[v[maxj]]))
					    maxj = j;
				}
			}
		}
	    
	}
	return ;
}
void MorningStar(){
	cin >> n >> m;
	ll sum = 0;
	while(m--){
		int u,v;
		ll w;
		cin >> u >> v >> w;
		//1-n 用这个 
		u--,v--;
		g[u][v] = w;
		g[v][u] = w;
		sum +=w;
	}
	res = 1e18+7;
	Mincut(n);
	sum-=res;
	cout << 2*sum <<endl;
	
}
int main(){
    IOS;
	rd();
	MorningStar();
    ot();
    return 0;
}

有向图强连通分量

vector<int> edge[N];
int dfn[N],low[N];
int id[N],siz[N];
int tot,scc_cnt;
int out[N];
stack<int> st;
bool book[N];
void tarjan(int u){
	dfn[u] = low[u] = ++tot;
	st.push(u);
	book[u] = 1;
	for(auto k : edge[u]){
		if(!dfn[k]){
			tarjan(k);
			low[u] = min(low[u],low[k]);
		}
		else if(book[k]) low[u] = min(low[u],dfn[k]);
	}
	if(dfn[u] == low[u]){
		++scc_cnt;
		int y;
		do{
			y = st.top();
			st.pop();
			book[y] = 0;
			id[y] = scc_cnt;
			siz[scc_cnt]++;
		}while(y != u);
	}
	
}

无向图双连通分量

1)点双连通分量
const int N = 1e4+7;
int n,m;
vector<int> edge[N];
int dfn[N], low[N], timestamp;
int stk[N], top;
int dcc_cnt;
vector<int> dcc[N];
bool is_cut[N];
int root;
int idx;
void add(int a,int b){
	edge[a].push_back(b);
}
void tarjan(int u){
	low[u] = dfn[u] = ++timestamp;
	stk[++top] = u;
	if(u == root && !edge[u].size()){
		dcc_cnt++;
		dcc[dcc_cnt].push_back(u);
		return;
	}
	
	int cnt = 0;
	for(auto j : edge[u]){
		if(!dfn[j]){
			tarjan(j);
			low[u] = min(low[u],low[j]);
			if(dfn[u] <= low[j]){
				cnt++;
				if(u != root || cnt > 1) is_cut[u] = true;
				++dcc_cnt;
				int y;
				do{
					y = stk[top--];
					dcc[dcc_cnt].push_back(y);
				}while(y != j);
				dcc[dcc_cnt].push_back(u);
			}
		}
		else low[u] = min(low[u],dfn[j]);
	}
}
void solve(int id){
	cout <<"Case "<<id<<": ";
	for(int i = 1; i <= dcc_cnt; i ++) dcc[i].clear();
	for(int i = 1; i <= n; i ++) edge[i].clear(); 
	top = 0;
	dcc_cnt = 0;
	timestamp = 0;
	n = 0;
	memset(dfn,0,sizeof dfn);
	memset(is_cut,0,sizeof is_cut);
	while(m --){
		int a,b;
		cin >> a >> b;
		n = max({n,a,b});
		add(a,b),add(b,a);
	}
	for(root = 1; root <= n; root ++){
		if(!dfn[root]) tarjan(root);
	}
	int res = 0;
	ull num = 1;
	//pf(dcc_cnt);
	for(int i = 1; i <= dcc_cnt; i ++){
		int cnt = 0;
		for(auto k : dcc[i]){
			if(is_cut[k]) cnt++;
		}
		if(cnt == 0){
			if(dcc[i].size() > 1) res += 2,num *=dcc[i].size()*(dcc[i].size()-1)/2;
			else res ++;
		}
		else if(cnt == 1){
			res++; num *= dcc[i].size()-1;
		}
	}
	cout << res <<" "<<num <<'\n';
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    while(cin >> m,m) solve(++idx);

    return 0;
}
2)边双连通分量
//这里用了邻接表来存图
const int N = 5010, M = 20010;
int n, m;
int h[N], e[M], ne[M], idx;
int dfn[N], low[N], timestamp;
int stk[N], top;
int id[N], dcc_cnt;
bool is_bridge[M];
int d[N];
void add(int a, int b){
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx ++;
}
void tarjan(int u, int from)
{
    dfn[u] = low[u] = ++ timestamp;
    stk[ ++ top] = u;

    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (!dfn[j])
        {
            tarjan(j, i);
            low[u] = min(low[u], low[j]);
            if (dfn[u] < low[j])
                is_bridge[i] = is_bridge[i ^ 1] = true;
        }
        else if (i != (from ^ 1))
            low[u] = min(low[u], dfn[j]);
    }

    if (dfn[u] == low[u])
    {
        ++ dcc_cnt;
        int y;
        do {
            y = stk[top -- ];
            id[y] = dcc_cnt;
        } while (y != u);
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    memset(h,-1,sizeof h);
    cin >> n >> m;
	while(m --) {
		int a,b;
		cin >> a >> b;
		add(a,b),add(b,a);
	}
	tarjan(1,-1);
	
	for(int i = 0; i < idx; i++){
		if(is_bridge[i]) d[id[e[i]]]++;
	}
	int cnt = 0;
	for(int i = 1; i <= dcc_cnt; i ++){
		if(d[i] == 1) cnt++;
	}
	cout << (cnt+1)/2;

    return 0;
}

最小生成树

const int N=2e5+7;
int p[N];
struct Edge{
	int a,b,w;
}edge[N];
bool cmp(Edge a,Edge b){
	return a.w<b.w;
}
int find(int x){
	if(p[x]!=x)p[x]=find(p[x]);
	return p[x];
}
int main(){
	int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
    	int a,b,c;
    	scanf("%d%d%d",&a,&b,&c);
    	edge[i].a=a;
    	edge[i].b=b;
    	edge[i].w=c;
	}
	fer(i,1,n)p[i]=i;
	sort(edge+1,edge+1+m,cmp);
	int res=0,cnt=0;
	for(int i=1;i<=m;i++){
		int a=edge[i].a,b=edge[i].b,w=edge[i].w;
		a=find(a),b=find(b);
		if(a!=b){
			p[a]=b;
			res+=w;
			cnt++;
		}
	}
	if(cnt!=n-1)puts("impossible");
	else pf(res);
    return 0;
}

次小生成树

#include <bits/stdc++.h>
#define ll long long
#define pf(x) cout<<"("<<__LINE__<<")"<<#x<<"="<<x<<endl
using namespace std;
const int N = 1e5+7;
const int INF = 0x3f3f3f3f;
int n,m;
vector<pair<int,int>> edge[N];
struct node{
	int a,b,c;
	bool used;
	bool operator < (const node a) const{
	    return c < a.c;
	}
}e[N]; 
int p[N];
int depth[N], fa[N][17], d1[N][17], d2[N][17];
void add(int a,int b,int c){
	edge[a].push_back({c,b});
}
int find(int x){
	if(p[x] != x) p[x] = find(p[x]);
	return p[x];
}
ll mst(){
	for(int i = 1; i <= n; i ++) p[i] = i;
	sort(e+1,e+1+m);
	ll res = 0;
	for(int i = 1; i <= m; i++){
		int a = e[i].a;
		int b = e[i].b;
		int c = e[i].c;
		a = find(a);
		b = find(b);
		if(a != b){
			p[a] = b;
			res += c;
			e[i].used = 1; 
		} 
	} 
	return res;
}
void build(){
	for(int i = 1; i <= m; i ++){
		if(e[i].used){
			int a = e[i].a;
		    int b = e[i].b;
		    int c = e[i].c;
		    add(a,b,c);
		    add(b,a,c);
		}
	}
}
void bfs(){
    memset(depth, 0x3f, sizeof depth);
    depth[0] = 0, depth[1] = 1;
    queue<int> q;
    q.push(1);
    while (!q.empty()){
        int pos = q.front();
        q.pop();
        for (auto pr : edge[pos]){
        	int w = pr.first;
        	int v = pr.second;
            if (depth[v] > depth[pos] + 1){
                depth[v] = depth[pos] + 1;
                q.push(v);
                fa[v][0] = pos;
                d1[v][0] = w, d2[v][0] = -INF;
                for (int k = 1; k <= 16; k ++ ){
                    int anc = fa[v][k - 1];
                    fa[v][k] = fa[anc][k - 1];
                    int distance[4] = {d1[v][k - 1], d2[v][k - 1], d1[anc][k - 1], d2[anc][k - 1]};
                    d1[v][k] = d2[v][k] = -INF;
                    for (int u = 0; u < 4; u ++ ){
                        int d = distance[u];
                        if (d > d1[v][k]) d2[v][k] = d1[v][k], d1[v][k] = d;
                        else if (d != d1[v][k] && d > d2[v][k]) d2[v][k] = d;
                    }
                }
            }
        }
    }
}
int lca(int a,int b,int w){
	static int distance[N * 2];
    int cnt = 0;
    if (depth[a] < depth[b]) swap(a, b);
    for (int k = 16; k >= 0; k -- ){
    	if (depth[fa[a][k]] >= depth[b]){
            distance[++cnt] = d1[a][k];
            distance[++cnt] = d2[a][k];
            a = fa[a][k];
        }
	}     
    if (a != b){
        for (int k = 16; k >= 0; k -- ){
        	if (fa[a][k] != fa[b][k]){
                distance[++cnt] = d1[a][k];
                distance[++cnt] = d2[a][k];
                distance[++cnt] = d1[b][k];
                distance[++cnt] = d2[b][k];
                a = fa[a][k], b = fa[b][k];
            }
		}  
        distance[++cnt] = d1[a][0];
        distance[++cnt] = d1[b][0];
    }

    int dist1 = -INF, dist2 = -INF;
    for (int i = 1; i <= cnt; i ++ ){
        int d = distance[i];
        if (d > dist1) dist2 = dist1, dist1 = d;
        else if (d != dist1 && d > dist2) dist2 = d;
    }

    if (w > dist1) return w - dist1;
    if (w > dist2) return w - dist2;
    return INF;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for(int i = 1; i <= m; i ++){
    	int a,b,c;
    	cin >> a >> b >> c;
    	e[i] = {a,b,c};
	}
	ll sum = mst();
	build();
	bfs();
	ll res = 1e18;
	for(int i = 1; i <= m; i ++){
		if(!e[i].used){
			int a = e[i].a;
			int b = e[i].b;
		    int c = e[i].c;
		    res = min(res,sum + lca(a,b,c));
		}
	}
	cout << res;

    return 0;
}

LCA

倍增
#include <bits/stdc++.h>
#define ll long long
#define pf(x) cout<<"("<<__LINE__<<")"<<#x<<"="<<x<<endl
using namespace std;
const int N = 4e4+7;
int depth[N];
int fa[N][20];
int n,m; 
vector<int> edge[N];
int root;
void add(int a,int b){
	edge[a].push_back(b);
}
void bfs(){
	memset(depth,0x3f,sizeof depth);
	queue<int> q;
	q.push(root);
	depth[0] = 0;
	depth[root] = 1;
	while(!q.empty()){
		int pos = q.front();
		q.pop();
		for(auto k : edge[pos]){
			if(depth[k] > depth[pos] + 1){
				depth[k] = depth[pos] + 1;
				q.push(k);
				fa[k][0] = pos;
				for(int j = 1;j<=15;j++){
					fa[k][j] = fa[fa[k][j-1]][j-1];
				}
			}
		}
	}
}
void dfs(int x,int u){
	for(auto k : edge[x]){
		if(k == u) continue;
		depth[k] = depth[x] + 1;
		fa[k][0] = x;
		for(int j = 1; j<= 15; j++){
			fa[k][j] = fa[fa[k][j-1]][j-1];
		}
		dfs(k,x);
	}
}
int lca(int a,int b){
	if(depth[a] < depth[b]) swap(a,b);
	for(int k = 15; k >= 0; k--){
		if(depth[fa[a][k]] >= depth[b]){
			a = fa[a][k];
		}
	}
	if(a == b) return a;
	for(int k = 15;k >= 0; k--){
		if(fa[a][k]!=fa[b][k]){
			a = fa[a][k];
			b = fa[b][k];
		}
	}
	return fa[a][0];
}

Tarjan
typedef pair<int,int> PII;
const int N = 2e4+7;
int n,m;
vector<PII> edge[N];
int st[N];
int depth[N];
int p[N];
int ans[N];
struct node{
	int v;
	int id;
};
vector<node> q[N];
int find(int x){
	if(p[x] != x) p[x] =  find(p[x]);
	return p[x];
}
void dfs(int x,int u){
	for(auto pr : edge[x]){
		int w = pr.first;
		int v = pr.second;
		if(v == u) continue;
		depth[v] = depth[x] + w;
		dfs(v,x);
	}
}
void tarjan(int x){
	st[x] = 1;
	for(auto pr : edge[x]){
		int v = pr.second;
		if(st[v] == 0){
			tarjan(v);
			p[v] = x;
		}
	}
	for(auto pr : q[x]){
		int id = pr.id;
		int v = pr.v;
		if(st[v] == 2){
			int fa = find(v);
			ans[id] = depth[x] + depth[v] - 2*depth[fa];
		} 
	}
	st[x] = 2;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for(int i = 1; i < n; i++){
    	int x,y,k;
    	cin >> x >> y >> k;
    	edge[x].push_back({k,y});
    	edge[y].push_back({k,x});
	}
	for(int i = 1; i <= m; i++){
		int x,y;
		cin >> x >> y;
		if(x != y){
			q[x].push_back({y,i});
		    q[y].push_back({x,i});
		}
	}
	for(int i = 1; i <= n; i++) p[i] = i;
	dfs(1,-1);
	tarjan(1);
	for(int i = 1; i <= m; i++) cout << ans[i] <<'\n'; 
    return 0;
}

3.数论

快速幂

ll ksm(ll a,ll b){
    ll res=1;
    while(b){
    	if(b&1)res=res*a%mod;
        b>>=1;
        a = a * a % mod;
    }
    return res;
}

NTT

#include <bits/stdc++.h>
#define ll long long
#define pf(x) cout<<"("<<__LINE__<<")"<<#x<<" ="<<x<<endl
using namespace std;
const ll mod = 998244353;
const int N = 4e6+10;
ll n,len;
ll jc[N],jc_inv[N];
ll a[N<<1],b[N<<1];
const ll G = 3,P = mod;
ll R[N<<1];
ll ksm(ll a, ll b){
	ll res = 1;
	while(b){
		if(b&1) res  = res * a %mod;
		a = a*a %mod;
		b >>= 1; 
	}
	return res;
}
void NTT(ll *a, ll f)
{
    for (ll i = 0; i < n; i++)
        if (i < R[i])
            swap(a[i], a[R[i]]);
    for (ll i = 1; i < n; i <<= 1)
    {
        ll gn = ksm(G, (P - 1) / (i << 1));
        for (ll j = 0; j < n; j += (i << 1))
        {
            ll g = 1;
            for (ll k = 0; k < i; k++, g = 1ll * g %P* gn % P)
            {
                ll x = a[j + k], y = 1ll * g%P * a[j + k + i] % P;
                a[j + k] = (x + y) % P;
                a[j + k + i] = (x - y + P) % P;
            }
        }
    }
    if (f == 1)
        return;
    int nv = ksm(n, P - 2);
    reverse(a + 1, a + n);
    for (int i = 0; i < n; i++)
        a[i] = 1ll * a[i] * nv % P;
}
void init(){
	jc[0] = 1;
	jc_inv[0] = 1;
	for(ll i = 1;i<=n;i++){
		jc[i] = jc[i-1]*i%mod;
		jc_inv[i] = ksm(jc[i],mod-2);
	}
	for(int i = 0; i < n;i++) R[i] = (R[i >> 1] >> 1) | ((i & 1) ? (n>>1): 0);
}
ll C(ll x, ll y){
	return jc[x] * jc_inv[y] % mod * jc_inv[x - y] % mod;
} 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
	cin >>len;
	n = 1;
	while(n<len) n<<=1;
	n <<= 1;
	init();

	for(ll i = 0; i <= len/3;i++){
		a[i] = jc[i] * C(len-2*i,i) %mod * ksm(26,len-3*i) %mod;
	}
	for(ll i = 0; i <= len; i++){
		b[i] = jc_inv[len-i] * ((len-i)%2==1?-1:1); 
	}
	NTT(a,1);
	NTT(b,1);
	for(ll i = 0; i<n;i++) a[i] = a[i] * b[i] % mod;
	NTT(a,-1);
	for(int i = 0;i <=len; i++){
		cout << (a[len+i] * jc_inv[i] % mod + mod )%mod<<' ';
	}

    return 0;
}




//second

#include <bits/stdc++.h>
#define int long long
#define poly vector<int>
#define len(x) ((int)x.size())
using namespace std;
const int N = 2e4 + 5, M = 35, g = 3, ginv = 332748118, mod = 998244353;
int n, m, rev[N], lim, liminv, cnt[35], fact[N], infact[N], res;
string str;
poly ans, tmp;
int qmi(int a, int b) {
    int res = 1;
    while (b) {
        if (b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}
void NTT(poly &f, int op) {
    for (int i = 0; i < lim; i ++) {
        if (i < rev[i]) swap(f[i], f[rev[i]]);
    }
    for (int mid = 1; mid < lim; mid <<= 1) {
        int gn = qmi(op == 1 ? g : ginv, (mod - 1) / (mid << 1));
        for (int i = 0; i < lim; i += mid * 2) {
            for (int j = 0, g0 = 1; j < mid; j ++, g0 = g0 * gn % mod) {
                int x = f[i + j], y = g0 * f[i + j + mid] % mod;
                f[i + j] = (x + y) % mod, f[i + j + mid] = (x - y + mod) % mod;
            }
        }
    }
    if (op == -1) {
        for (int i = 0; i < lim; i ++) f[i] = f[i] * liminv % mod;
    }
}
poly operator * (poly f, poly g) {
    int n = len(f) + len(g) - 1;
    for (lim = 1; lim < n; lim <<= 1); liminv = qmi(lim, mod - 2);
    for(int i = 0; i < lim; i ++) rev[i] = (rev[i >> 1] >> 1) | (i & 1 ? lim >> 1 : 0);
    f.resize(lim), g.resize(lim);
    NTT(f, 1), NTT(g, 1);
    for (int i = 0; i < lim; i ++) f[i] = f[i] * g[i] % mod;
    NTT(f, -1), f.resize(n);
    return f;
}
signed main() {
    fact[0] = infact[0] = 1;
    for (int i = 1; i < N; i ++) {
        fact[i] = fact[i - 1] * i % mod;
        infact[i] = infact[i - 1] * qmi(i, mod - 2) % mod;
    }
    cin >> str;
    for (int i = 0; i < str.size(); i ++) {
        cnt[str[i] - 'a'+1] ++;
    }
    ans.resize(cnt[1] + 1);
    for (int i = 0; i <= cnt[1]; i ++) {
        ans[i] = infact[i];
    }
    for (int i = 2; i <= 26; i ++) {
        tmp.resize(cnt[i] + 1);
        for (int j = 0; j <= cnt[i]; j ++) {
            tmp[j] = infact[j];
        }
        ans = ans * tmp;
    }
    for (int i = 1; i < len(ans); i ++) {
        res = (res + fact[i] * ans[i] % mod) % mod;
    }
    cout << res ;
}

中国剩余定理

ll crt(){
    ll ans = 0;
    ll p = mod-1;
    for(int i=0; i<4; i++)
    {
        ll tmp = p/prime[i];
        ans = (ans + tmp*ksm(tmp,prime[i]-2,prime[i])%p*num[i]%p)%p;
    }
    return ans;
}

欧拉降幂

a b = { a b % ϕ ( p ) g c d ( a , p ) = 1 a b g c d ( a , p ) ≠ 1 , b < ϕ ( p ) a b % ϕ ( p ) + ϕ ( p ) g c d ( a , p ) ≠ 1 , b ≥ ϕ ( p ) a^b = \begin{cases} a^{b\%\phi(p)} & gcd(a,p)=1 \\ a^b & gcd(a,p)\ne1,b<\phi(p) \\ a^{b\%\phi(p)+\phi(p)} & gcd(a,p)\ne1,b\geq\phi(p) \\ \end{cases} ab= ab%ϕ(p)abab%ϕ(p)+ϕ(p)gcd(a,p)=1gcd(a,p)=1,b<ϕ(p)gcd(a,p)=1,bϕ(p)

ll euler(ll x){
    ll res = x;
    for(ll i=2; i*i<=x; i++)
        if(x % i == 0){
             res = res / i * (i - 1);
             while(x % i == 0) x /= i;
         }
    if(x > 1) res = res / x * (x - 1);
    return res;
}

欧拉筛

int prime[N+5],st[N+5];
int cnt=0;
void getprime(int n){
	fer(i,2,n){
		if(!st[i]) prime[cnt++]=i;
		for(int j=0;prime[j]<=n/i;j++){
			st[prime[j]*i]=true;
			if(i%prime[j]==0)break;
		}
	}
}

拓展欧几里得

int exgcd(int a,int b,int &x,int &y){
	if(b==0){
		x=1,y=0;
		return a;
	}
	int x1,y1,gcd;
	gcd=exgcd(b,a%b,x1,y1);
	x=y1,y=x1-a/b*y1;
	return gcd;
} 
int main(){
	int a,b,x,y,n;cin>>n;
	while(n--){
		cin>>a>>b;
		exgcd(a,b,x,y);
		cout<<x<<' '<<y<<endl;
	}
    return 0;
}

线性基

for(int i = 1;i<=n;i++){
        ll tmp = a[i];
        for(int j = 52;j>=0;j--){
            if(((tmp >> j) & 1) == 0) continue;
            if(p[j] == 0){
                p[j] = tmp;
                break;
            }
            else tmp ^= p[j];
        }
}

矩阵快速幂

const int N = 3;
struct mat{
	ll m[N][N];
	void init(){
		memset(m,0,sizeof m);
	}
};
mat mul(mat x,mat y,ll mod){
	mat res;
	ll t = 0;
	for(int i = 0; i <= n; i++){
		for(int j = 0; j <= n; j++){
			t = 0;
			for(int k = 0; k <= n; k++){
				t+= (x.m[i][k]%mod)*(y.m[k][j]%mod) % mod;
				t%=mod;
			}
			res.m[i][j] = t % mod;
		}
	}
	return res;
}
mat mat_qmi(mat a, ll k, ll mod){
	mat res;
	for(int i = 0; i <= n; i++){
		for(int j = 0; j <= n; j++){
			if(i == j) res.m[i][j] = 1;
			else res.m[i][j] = 0;
		}
	}
	while(k){
		if(k&1) res = mul(res,a,mod);
		a = mul(a,a,mod);
		k>>=1;
	}
	return res;
}
ll qmi(ll x, ll b,ll mod){
	ll res = 1;
	while(b){
		if(b&1) res = res*x%mod;
		x=x*x%mod;
		b>>=1;
	}
	return res;
}
ll euler(ll x){
    ll res = x;
    for(ll i=2; i*i<=x; i++)
        if(x % i == 0){
             res = res / i * (i - 1);
             while(x % i == 0) x /= i;
         }
    if(x > 1) res = res / x * (x - 1);
    return res;
}
int main(){
    IOS;
	int TT;
	TT = 1;
	cin >> TT;
	while(TT--){
	ll n,mod;
	cin >> n >> mod;
    mat init;
    fer(i, 0, 2)fer(j, 0, 2) init.m[i][j] = 0;
	init.m[0][0] =1; init.m[0][1] =1; init.m[0][2] = 0;
	
    mat a;
    a.m[0][0] = 0;a.m[0][1] = 1;a.m[0][2] = 0;
    a.m[1][0] = 1;a.m[1][1] = 1;a.m[1][2] = 1;
    a.m[2][0] = 0;a.m[2][1] = 0;a.m[2][2] = 1;
    
    n = (ll)6*n;
    mat tmp,ans;
    tmp = mat_qmi(a,n,mod);
    ans = mul(init,tmp,mod);
    ll ans1 = ans.m[0][2];
    
    ll MOD = euler(mod);
    tmp = mat_qmi(a,n,MOD);
    ans = mul(init,tmp,MOD);
	
    ll t = ans.m[0][2];
    
    ll ans2 = qmi(2,t,mod);
    cout << ans1 <<" "<< ans2;
    if(TT!=0) cout <<'\n';
	}
    return 0;
}

4.搜索

DFS

求连通块数量
int dx[]={0,0,1,-1,1,-1,1,-1};
int dy[]={1,-1,0,0,1,1,-1,-1};
int book[N][N];
int num,n,m;
char mp[N][N];
void dfs(int x,int y){
	if(mp[x][y]=='*'||x<1||x>n||y<1||y>m||book[x][y]!=0)
	return ;
	book[x][y]=num;
	for(int j=0;j<=7;j++){
		int tx=x+dx[j];
		int ty=y+dy[j];
		if(mp[tx][ty]=='@'&&tx>=1&&tx<=n&&ty>=1&&ty<=m)
		dfs(tx,ty);
	}
} 
int main(){
    while(cin>>n>>m,n+m){
    	num=0;
    	memset(book,0,sizeof(book));
    	for(int i=1;i<=n;i++)
    	for(int j=1;j<=m;j++)
    	cin>>mp[i][j];
    	for( int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			if(mp[i][j]=='@'&&book[i][j]==0)
    			        num++;
				dfs(i,j);
    			
			}
		}
		cout<<num<<endl;
	}
    return 0;
}

5.动态规划

数位dp

int dp[15][15];
int a[15];
ll dfs(ll pos,bool limit,int pre,int lead){
	if(pos == 0) return !lead;
	if(!limit && dp[pos][pre] != -1 && !lead) return dp[pos][pre];
	int up = limit ? a[pos] : 9;
	ll tot = 0;
	for(int i = 0;i<=up;i++){
		if(!lead){
			if(abs(i-pre)>=2) tot+=dfs(pos-1,limit && i == up,i,0);
		}
		else tot += dfs(pos-1,limit && i == up,i,i==0);
	}
	if(!lead && !limit) return dp[pos][pre] = tot;
	return tot;
}
ll solve(ll x){
	int pos = 0;
	while(x){
		a[++pos] = x%10;
		x /=10;
	}
	return dfs(pos,1,-1,1);
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    ll a,b;
    cin >> a >> b;
    memset(dp,-1,sizeof dp);
    cout << solve(b)-solve(a-1);

    return 0;
}

斜率优化dp

ll f[N];
ll a[N];
ll b[N];
int q[N];
int s[N];
ll l,n;
ll y(int i){
	return f[i] + b[i]*b[i];
} 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> l;
    for(int i = 1; i <= n; i ++){
    	cin >> s[i];
    	s[i] += s[i-1];
	}
	for(int i = 0; i <= n; i ++){
		a[i] = s[i] + i;
		b[i] = a[i] + l + 1;
	}
	int hh = 0;
	int tt = 0;
	q[0] = 0;
	for(int i = 1; i <= n; i ++){
		while(hh < tt && (y(q[hh+1])-y(q[hh]))<=2*a[i]*(b[q[hh+1]]-b[q[hh]]))hh++;
		f[i] = f[q[hh]] + (a[i] - b[q[hh]])*(a[i] - b[q[hh]]);
		while(hh < tt && (y(q[tt])-y(q[tt-1]))*(b[i]-b[q[tt]])>=(y(i)-y(q[tt]))*(b[q[tt]]-b[q[tt-1]]))tt--;
		q[++tt] = i;
		//pf(f[i]);
	}
	cout << f[n];
    return 0;
}

$f[i]={x_i+y_i\choose x_i} - \sum\limits_{x_j<=x_i\ ,\ y_j<=y_i\ ,\ j\neq i}{x_i-x_j+y_i-y_j\choose x_i-x_j}*f[j] $

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值