【算法竞赛】好用的模版/注意要点

【算法竞赛】一些好用的模版/注意要点

火车头(2026.07.06更新)

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define whiteink signed main
#define fi first
#define sc second

#define YES cout<<"YES"<<endl
#define NO cout<<"NO"<<endl
#define Yes cout<<"Yes"<<endl
#define No cout<<"No"<<endl
#define yes cout<<"yes"<<endl
#define no cout<<"no"<<endl

#define pb push_back
#define pq priority_queue
#define all(x) x.begin(),x.end()

using i64=long long;
using i128=__int128;
using u64=unsigned long long;
using u128 = unsigned __int128;
typedef pair<int,int> PII;
typedef pair<i64,i64> P64;
typedef long double ld;
typedef pair<long double,long double> Pld;

mt19937_64 rng;
//std::random_device rd;
//unsigned int seed = rd();
//rng.seed(seed);
//rng();

template<typename T>
T whink_max(T a,T b){return a>b?a:b;}
template<typename T>
T whink_min(T a,T b){return a<b?a:b;}
template<typename T>
bool cmp(T a,T b){return a>b;}

const int inf_int=0x3f3f3f3f;
const i64 inf_i64=0x3f3f3f3f3f3f3f3f;
const i64 mod=998244353LL;

int dx[8]={1,0,-1,0,1,1,-1,-1},dy[8]={0,1,0,-1,1,-1,1,-1};

//快读快写
inline char nc(){ 
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2 && (p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}

template <typename T> void read(T &x){
    x=0;
    T f=1;
    char ch=nc();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=nc();
    }
    while(ch>='0' && ch<='9'){
        x=x*10+ch-'0';
        ch=nc();
    }
    x*=f;
}

template <typename T> void write(T x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9) write(x/10);
    putchar(x%10+'0');
}

//快速幂
i64 qmi(i64 a,i64 k,i64 p){
    a%=p;
	i64 res=1LL;
	while(k){
		if(k&1LL) res=res*a%p;
		k>>=1LL;//删去k的末位 
		a=a*a%p;
	}
	return res;
}

//gcd
i64 gcd(i64 a,i64 b){
	return b?gcd(b,a%b):a;
}

//求约数
vector<i64> get_divisors(i64 qaq){
	vector<i64> res;
	for(i64 i=1;i<=qaq/i;i++){
		if(qaq%i==0){
			res.push_back(i);
			if(i!=qaq/i) res.push_back(qaq/i);
		}
	}
	sort(res.begin(),res.end());
	return res;
}

//线性筛求质数序列
const int PRIMES_MAXN=1e6+10;
int primes_cnt=0;
vector<i64> primes;
vector<bool> primes_st;
void get_primes(int qaq){
	primes.resize(PRIMES_MAXN,0);
	primes_st.resize(PRIMES_MAXN,0);
	for(int i=2;i<=qaq;i++){
		if(!primes_st[i]) primes[primes_cnt++]=i;
		for(int j=0;primes[j]<=qaq/i;j++){
			primes_st[primes[j]*i]=true;
			if(i%primes[j]==0) break;
		}
	}
}

//组合数;使用时记得反过来!
const int FACT_MAX=1e6+10;
vector<i64> fact;      // 存储阶乘
vector<i64> inv_fact;  // 存储阶乘的逆元
void precompute(){
	fact.resize(FACT_MAX,0);
	inv_fact.resize(FACT_MAX,0);
    fact[0]=1;
    for(int i=1;i<FACT_MAX;i++) {
        fact[i]=fact[i-1]*i%mod;
    }
    inv_fact[FACT_MAX-1]=qmi(fact[FACT_MAX-1],mod-2LL,mod);
    for(int i=FACT_MAX-2;i>=0;i--){
        inv_fact[i]=inv_fact[i+1]*(i+1)%mod;
    }
}
i64 C(i64 n,i64 k) {
    if(n<0 || k<0 || n<k) return 0;
    return fact[n]*inv_fact[k]%mod*inv_fact[n-k]%mod;
}
i64 A(i64 n,i64 k) {
    if(n<0 || k<0 || n<k) return 0;
    return fact[n]*inv_fact[n-k]%mod;
}

const int N=3e5+10;
int n;

void solve(){
    
    
}

whiteink(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    //precompute();
    //get_primes(1e6);

    int T=1;
    cin>>T;
    while(T--) solve();
    return 0;
}

注:换成vector+resize是因为会卡常(悲
image

取模运算类

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define whiteink signed main
#define fi first
#define sc second

using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
 
using u128 = unsigned __int128;
using i128 = __int128;

template<class T>
constexpr T power(T a, u64 b, T res = 1) {
    for (; b != 0; b /= 2, a *= a) {
        if (b & 1) {
            res *= a;
        }
    }
    return res;
}
 
template<u32 P>
constexpr u32 mulMod(u32 a, u32 b) {
    return u64(a) * b % P;
}
 
template<u64 P>
constexpr u64 mulMod(u64 a, u64 b) {
    u64 res = a * b - u64(1.L * a * b / P - 0.5L) * P;
    res %= P;
    return res;
}
 
constexpr i64 safeMod(i64 x, i64 m) {
    x %= m;
    if (x < 0) {
        x += m;
    }
    return x;
}
 
constexpr std::pair<i64, i64> invGcd(i64 a, i64 b) {
    a = safeMod(a, b);
    if (a == 0) {
        return {b, 0};
    }
    
    i64 s = b, t = a;
    i64 m0 = 0, m1 = 1;
 
    while (t) {
        i64 u = s / t;
        s -= t * u;
        m0 -= m1 * u;
        
        std::swap(s, t);
        std::swap(m0, m1);
    }
    
    if (m0 < 0) {
        m0 += b / s;
    }
    
    return {s, m0};
}
 
template<std::unsigned_integral U, U P>
struct ModIntBase {
public:
    constexpr ModIntBase() : x(0) {}
    template<std::unsigned_integral T>
    constexpr ModIntBase(T x_) : x(x_ % mod()) {}
    template<std::signed_integral T>
    constexpr ModIntBase(T x_) {
        using S = std::make_signed_t<U>;
        S v = x_ % S(mod());
        if (v < 0) {
            v += mod();
        }
        x = v;
    }
    
    constexpr static U mod() {
        return P;
    }
    
    constexpr U val() const {
        return x;
    }
    
    constexpr ModIntBase operator-() const {
        ModIntBase res;
        res.x = (x == 0 ? 0 : mod() - x);
        return res;
    }
    
    constexpr ModIntBase inv() const {
        auto v = invGcd(x, mod());
        assert(v.first == 1);
        return v.second;
    }
    
    constexpr ModIntBase &operator*=(const ModIntBase &rhs) & {
        x = mulMod<mod()>(x, rhs.val());
        return *this;
    }
    constexpr ModIntBase &operator+=(const ModIntBase &rhs) & {
        x += rhs.val();
        if (x >= mod()) {
            x -= mod();
        }
        return *this;
    }
    constexpr ModIntBase &operator-=(const ModIntBase &rhs) & {
        x -= rhs.val();
        if (x >= mod()) {
            x += mod();
        }
        return *this;
    }
    constexpr ModIntBase &operator/=(const ModIntBase &rhs) & {
        return *this *= rhs.inv();
    }
    
    friend constexpr ModIntBase operator*(ModIntBase lhs, const ModIntBase &rhs) {
        lhs *= rhs;
        return lhs;
    }
    friend constexpr ModIntBase operator+(ModIntBase lhs, const ModIntBase &rhs) {
        lhs += rhs;
        return lhs;
    }
    friend constexpr ModIntBase operator-(ModIntBase lhs, const ModIntBase &rhs) {
        lhs -= rhs;
        return lhs;
    }
    friend constexpr ModIntBase operator/(ModIntBase lhs, const ModIntBase &rhs) {
        lhs /= rhs;
        return lhs;
    }
    
    friend constexpr std::istream &operator>>(std::istream &is, ModIntBase &a) {
        i64 i;
        is >> i;
        a = i;
        return is;
    }
    friend constexpr std::ostream &operator<<(std::ostream &os, const ModIntBase &a) {
        return os << a.val();
    }
    
    friend constexpr bool operator==(const ModIntBase &lhs, const ModIntBase &rhs) {
        return lhs.val() == rhs.val();
    }
    friend constexpr std::strong_ordering operator<=>(const ModIntBase &lhs, const ModIntBase &rhs) {
        return lhs.val() <=> rhs.val();
    }
    
private:
    U x;
};
 
template<u32 P>
using ModInt = ModIntBase<u32, P>;
template<u64 P>
using ModInt64 = ModIntBase<u64, P>;
 
struct Barrett {
public:
    Barrett(u32 m_) : m(m_), im((u64)(-1) / m_ + 1) {}
 
    constexpr u32 mod() const {
        return m;
    }
 
    constexpr u32 mul(u32 a, u32 b) const {
        u64 z = a;
        z *= b;
        
        u64 x = u64((u128(z) * im) >> 64);
        
        u32 v = u32(z - x * m);
        if (m <= v) {
            v += m;
        }
        return v;
    }
 
private:
    u32 m;
    u64 im;
};
 
template<u32 Id>
struct DynModInt {
public:
    constexpr DynModInt() : x(0) {}
    template<std::unsigned_integral T>
    constexpr DynModInt(T x_) : x(x_ % mod()) {}
    template<std::signed_integral T>
    constexpr DynModInt(T x_) {
        int v = x_ % int(mod());
        if (v < 0) {
            v += mod();
        }
        x = v;
    }
    
    constexpr static void setMod(u32 m) {
        bt = m;
    }
    
    static u32 mod() {
        return bt.mod();
    }
    
    constexpr u32 val() const {
        return x;
    }
    
    constexpr DynModInt operator-() const {
        DynModInt res;
        res.x = (x == 0 ? 0 : mod() - x);
        return res;
    }
    
    constexpr DynModInt inv() const {
        auto v = invGcd(x, mod());
        assert(v.first == 1);
        return v.second;
    }
    
    constexpr DynModInt &operator*=(const DynModInt &rhs) & {
        x = bt.mul(x, rhs.val());
        return *this;
    }
    constexpr DynModInt &operator+=(const DynModInt &rhs) & {
        x += rhs.val();
        if (x >= mod()) {
            x -= mod();
        }
        return *this;
    }
    constexpr DynModInt &operator-=(const DynModInt &rhs) & {
        x -= rhs.val();
        if (x >= mod()) {
            x += mod();
        }
        return *this;
    }
    constexpr DynModInt &operator/=(const DynModInt &rhs) & {
        return *this *= rhs.inv();
    }
    
    friend constexpr DynModInt operator*(DynModInt lhs, const DynModInt &rhs) {
        lhs *= rhs;
        return lhs;
    }
    friend constexpr DynModInt operator+(DynModInt lhs, const DynModInt &rhs) {
        lhs += rhs;
        return lhs;
    }
    friend constexpr DynModInt operator-(DynModInt lhs, const DynModInt &rhs) {
        lhs -= rhs;
        return lhs;
    }
    friend constexpr DynModInt operator/(DynModInt lhs, const DynModInt &rhs) {
        lhs /= rhs;
        return lhs;
    }
    
    friend constexpr std::istream &operator>>(std::istream &is, DynModInt &a) {
        i64 i;
        is >> i;
        a = i;
        return is;
    }
    friend constexpr std::ostream &operator<<(std::ostream &os, const DynModInt &a) {
        return os << a.val();
    }
    
    friend constexpr bool operator==(const DynModInt &lhs, const DynModInt &rhs) {
        return lhs.val() == rhs.val();
    }
    friend constexpr std::strong_ordering operator<=>(const DynModInt &lhs, const DynModInt &rhs) {
        return lhs.val() <=> rhs.val();
    }
    
private:
    u32 x;
    static Barrett bt;
};
 
template<u32 Id>
Barrett DynModInt<Id>::bt = 998244353;
 
using Z = ModInt<998244353>;
 
struct Comb {
    int n;
    std::vector<Z> _fac;
    std::vector<Z> _invfac;
    std::vector<Z> _inv;
    
    Comb() : n{0}, _fac{1}, _invfac{1}, _inv{0} {}
    Comb(int n) : Comb() {
        init(n);
    }
    
    void init(int m) {
        if (m <= n) return;
        _fac.resize(m + 1);
        _invfac.resize(m + 1);
        _inv.resize(m + 1);
        
        for (int i = n + 1; i <= m; i++) {
            _fac[i] = _fac[i - 1] * i;
        }
        _invfac[m] = _fac[m].inv();
        for (int i = m; i > n; i--) {
            _invfac[i - 1] = _invfac[i] * i;
            _inv[i] = _invfac[i] * _fac[i - 1];
        }
        n = m;
    }
    
    Z fac(int m) {
        if (m > n) init(2 * m);
        return _fac[m];
    }
    Z invfac(int m) {
        if (m > n) init(2 * m);
        return _invfac[m];
    }
    Z inv(int m) {
        if (m > n) init(2 * m);
        return _inv[m];
    }
    Z binom(int n, int m) {
        if (n < m || m < 0) return 0;
        return fac(n) * invfac(m) * invfac(n - m);
    }
} comb;
 
void solve() {
    
}
 
whiteink() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    int T=1;
    cin>>T;
    while(T--) solve();
    return 0;
}

大根堆和小根堆

//默认大根堆:less<>
priority_queue<int>
priority_queue<long long,vector<long long>,less<long long>>
//小根堆:greater<>
priority_queue<int,vector<int>,greater<int>>

//结构体:重载运算符
//priority_queue 默认会去查找 operator< 来决定元素间的大小关系
/*
【小于号大根堆】
【大于号小根堆】
*/
//大根堆
struct node{
    int value;
    friend bool operator<(const node &a,const node &b){
        return a.value<b.value; //【小于号大根堆】
    }
};
priority_queue<node>q;
//小根堆
struct node{
    int value;
    friend bool operator<(const node &a,const node &b){
        return a.value>b.value; //【大于号小根堆】
    }
};
priority_queue<node>q;

关闭同步流

->尽量都用cin和cout输入输出->简洁

//注意别和printf和scanf混用
//换行少用endl,多用'\n'
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
//保留n位小数
cout << fixed << setprecision(n) << 变量名 << '\n';

快读快写

//快读快写
inline char nc(){ 
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2 && (p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}

template <typename T> void read(T &x){
    x=0;
    T f=1;
    char ch=nc();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=nc();
    }
    while(ch>='0' && ch<='9'){
        x=x*10+ch-'0';
        ch=nc();
    }
    x*=f;
}

template <typename T> void write(T x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9) write(x/10);
    putchar(x%10+'0');
}

注意

(1)用nc()读字符串时:要判断nc()!='\0'
(2)注意换行输出putchar('\n')

高精度逃课大法:__int128

※最大38位
※一定要注意两个下划线!!!
快读inline int改为__int128
快写int改为__int128
变量名__int128

读取整行 + 字符串解析

//先忽略换行符
cin.ignore();
string line;
getline(cin, line);
stringstream ss(line);
int x;
while (ss >> x) {
    // 逐个读入
}

读到文件末尾为止

int a, b;
while(cin >> a >> b) {
    // 多组测试样例
}
//加EOF
while(scanf("%d%d", &a, &b) != EOF) {
    ...
}

关于vector

排序+去重

有时候可以不用set,省一个log的复杂度

sort(q.begin(),q.end());
q.erase(unique(q.begin(),q.end()),q.end());

枚举排列

vector<int> p(n);
//p[i]=i;
iota(p.begin(),p.end(),0);
//枚举每个排列 复杂度O(n!*n)->
do{
	//p变成了下标数组
	for(auto i : p){
		a[i] xxxx
	}
}
while(next_permutation(p.begin(),p.end()));

set/multiset遍历:迭代器iterator

升序输出

set<int>::iterator it;
for(it=mySet.begin();it!=mySet.end();it++) cout<<*it<<endl;

倒序输出:反向迭代器reverse_iterator``rbegin``rend

set<int>::reverse_iterator it;
for(it=mySet.rbegin();it!=mySet.rend();it++) cout<<*it<<endl;

高精度

高精度加

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
vector<int> A,B;
string a,b;
vector<int> add(vector<int> &A,vector<int> &B){
    	vector<int> C;
    	int t=0;
    	for(int i=0;i<A.size()||i<B.size();i++){
        	if(i<A.size()) t+=A[i];
        	if(i<B.size()) t+=B[i];
        	C.push_back(t%10) ;
        	t/=10;
    	}
    	if(t) C.push_back(1);
    	return C;
}
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      cin>>a>>b;
      for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
      for(int i=b.size()-1;i>=0;i--) B.push_back(b[i]-'0');
      vector<int> C=add(A,B);
      for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
      return 0;
}

高精度减

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
bool cmp(vector<int> &A,vector<int> &B) {//判断A是否>=B 
    	if(A.size()!=B.size()) return A.size()>B.size();
    	for(int i=A.size()-1;i>=0;i--){
        	if(A[i]!=B[i]) return A[i]>B[i];
    	} 
   	 return true;
}
vector<int> sub(vector<int> &A,vector<int> &B){//C=A-B 前提条件A>=B 
    	vector<int> C;
    	int t=0;
    	for(int i=0;i<A.size();i++){
        	t=A[i]-t;
        	if(i<B.size()) t-=B[i];
        	C.push_back((t+10)%10);
        	if(t<0) t=1; 
        	else t=0;
    	}
    	//处理前导0
    	while(C.size()>1 && C.back()==0) C.pop_back();
    	return C; 
}
signed main(){
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout.tie(0);
        vector<int> A,B;
    	string a,b;
    	cin>>a>>b;
    	for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
    	for(int i=b.size()-1;i>=0;i--) B.push_back(b[i]-'0');
    	if(cmp(A,B)){
        	vector<int> C=sub(A,B);
        	for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
    	}
    	else{
        	vector<int> C=sub(B,A);
        	printf("%c",'-');
        	for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
	}
        return 0;
}

高精度乘


高精度除

lambda函数

写check
写sort中的cmp
写大模拟

auto 函数名=[&/空白](引用的变量)->返回的数据类型 { 函数体 };

注意:lambda如果是auto型不能递归->要用function

function<void(int)> dfs=[&](int u)->void{
		if(u==n+1){
			for(int i=1;i<=n;i++){
				cout<<ans[i]<<" ";
			}
			cout<<endl;
		}
		for(int i=1;i<=n;i++){
			if(!st[i]){
				ans[u]=i;
				st[i]=1;
				dfs(u+1);
				st[i]=0;
			}
		}
	};

O3优化(慎用(x

#pragma GCC optimize(3)
#pragma GCC target("avx","f16c","sse3","sse2","sse1")
#pragma GCC target("avx","sse4","sse4.1","sse4.2","ssse3")
#pragma GCC optimize("Ofast","-fgcse","-fgcse-lm","-fipa-sra")
#pragma GCC optimize("-ffast-math","-fpeephole2","-fsched-spec")
#pragma GCC optimize("unroll-loops","-falign-jumps","-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("unroll-loops","no-stack-protector")
posted @ 2025-01-12 15:56  White_ink  阅读(68)  评论(0)    收藏  举报