【算法竞赛】好用的模版/注意要点
【算法竞赛】一些好用的模版/注意要点
火车头(2025.10.03更新)
#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
using i64=long long;
using i128=__int128;
typedef pair<int,int> PII;
typedef pair<i64,i64> P64;
typedef long double ld;
typedef pair<long double,long double> Pld;
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<int> get_divisors(int qaq){
vector<int> res;
for(int 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=5e7+10;
int primes_cnt=0;
vector<int> 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();
int T=1;
cin>>T;
while(T--) solve();
return 0;
}
注:换成vector+resize是因为会卡常(悲
取模运算类
#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 i128=__int128;
typedef pair<int,int> PII;
typedef pair<i64,i64> P64;
typedef long double ld;
typedef pair<long double,long double> Pld;
i64 max64(i64 a,i64 b){return a>b?a:b;}
i64 min64(i64 a,i64 b){return a<b?a:b;}
bool cmp(int a,int b){return a>b;}
bool cmp64(i64 a,i64 b){return a>b;}
const int inf_int=0x3f3f3f3f;
const i64 inf_i64=0x3f3f3f3f3f3f3f3f;
const i64 mod=1e9+7;
int dx[8]={1,0,-1,0,1,1,-1,-1},dy[8]={0,1,0,-1,1,-1,1,-1};
template<typename T>
constexpr T qmi(T x,i64 p){
T res=1;
while(p){
if(p&1)res*=x;
x*=x,p>>=1;
}
return res;
}
template<typename T,T P>
struct ModInt{
T x;
constexpr ModInt():x(){}
constexpr ModInt(i64 x_val):x(norm(x_val%getMod())){}
constexpr T val()const{return x;}
static T Mod;
constexpr static T getMod(){
return (P>0)?P:Mod;
}
constexpr static void setMod(T Mod_){Mod=Mod_;}
constexpr T norm(T x)const{
if(x<0)x+=getMod();
if(x>=getMod())x-=getMod();
return x;
}
static constexpr int mul(int a,int b,int mod){
return 1LL*a*b%mod;
}
static constexpr i64 mul(i64 a,i64 b,i64 mod){
i64 res=a*b-(i64)(1.l*a*b/mod)*mod;
res%=mod;
if(res<0)res+=mod;
return res;
}
explicit constexpr operator T()const{return x;}
constexpr ModInt operator-()const{
return norm(getMod()-x);
}
constexpr ModInt inv()const{
assert(x!=0);
return qmi(*this,getMod()-2);
}
constexpr ModInt& operator+=(ModInt rhs){
x=norm(x+rhs.x);
return *this;
}
constexpr ModInt& operator-=(ModInt rhs){
x=norm(x-rhs.x);
return *this;
}
constexpr ModInt& operator*=(ModInt rhs){
x=mul(x,rhs.x,getMod());
return *this;
}
constexpr ModInt& operator/=(ModInt rhs){
return *this*=rhs.inv();
}
friend constexpr ModInt operator+(ModInt lhs,ModInt rhs){return lhs+=rhs;}
friend constexpr ModInt operator-(ModInt lhs,ModInt rhs){return lhs-=rhs;}
friend constexpr ModInt operator*(ModInt lhs,ModInt rhs){return lhs*=rhs;}
friend constexpr ModInt operator/(ModInt lhs,ModInt rhs){return lhs/=rhs;}
friend constexpr bool operator==(ModInt lhs,ModInt rhs){return lhs.val()==rhs.val();}
friend constexpr bool operator!=(ModInt lhs,ModInt rhs){return lhs.val()!=rhs.val();}
friend constexpr bool operator<(ModInt lhs,ModInt rhs){return lhs.val()<rhs.val();}
friend constexpr bool operator<=(ModInt lhs,ModInt rhs){return lhs.val()<=rhs.val();}
friend constexpr bool operator>(ModInt lhs,ModInt rhs){return lhs.val()>rhs.val();}
friend constexpr bool operator>=(ModInt lhs,ModInt rhs){return lhs.val()>=rhs.val();}
friend constexpr istream& operator>>(istream& is,ModInt& in){
i64 v;
is>>v;
in=ModInt(v);
return is;
}
friend constexpr ostream& operator<<(ostream& os,const ModInt& out){
return os<<out.val();
}
};
template<typename T,T P>
T ModInt<T,P>::Mod=P;
const int N=3e5+10;
using mint=ModInt<i64,1000000000000000009LL>;
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
关于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")