模板大全
【永远置顶】万能程序模板
#include<bits/stdc++.h>
using namespace std;
//#define Inc
#ifdef Inc
#include<bits/extc++.h>
#include<windows.h>
#endif
#define Define
#ifdef Define
#define up(_name_,_leftbound_,_rightbound_) for(auto _name_=(_leftbound_);(_name_)<=(_rightbound_);++(_name_))
#define dn(_name_,_leftbound_,_rightbound_) for(auto _name_=(_leftbound_);(_name_)>=(_rightbound_);--(_name_))
#define For(_an_iterator_,_an_big_array_) for(auto _an_iterator_:_an_big_array_)
#define DEBUG cerr<<"---DEBUG---\n"<<__LINE__<<"\n-----------\n"
#define ll long long
#define ull unsigned long long
#define un unsigned
#define il inline
#define re register
#define i128 __int128
#define endl '\n'
#define db double
#define ld long double
#define Log(_shang_,_xia_) (log(_shang_)/log(_xia_))
#define _1 first
#define _2 second
#define mkp make_pair
#define pb(_Num_) push_back(_Num_)
#define pq priority_queue
#define pii pair<int,int>
#define to0(_an_array_) memset(_an_array_,0,sizeof(_an_array_))
#define toinf(_an_array_) memset(_an_array_,0x3f,sizeof(_an_array_))
#define qxx(_an_iterator_,_an_from_) for(auto _an_iterator_=head[_an_from_];_an_iterator_;_an_iterator_=e[_an_iterator_].nxt)
#define Ent cout<<endl
#define put(_an_num_) cout<<(_an_num_)<<endl
constexpr int inf=0x3f3f3f3f;
constexpr int mod=1e9+7;
constexpr ll mod2=212370440130137957;
constexpr int base=1331;
il ll read(){
ll x=0,f=1;char tmp=getchar();
while(!isdigit(tmp)){if(tmp=='-') f=-1;tmp=getchar();}
while(isdigit(tmp)){x=x*10+tmp-'0';tmp=getchar();}
return x*f;
}
ll Pow(ll a,ll b,ll mod){
ll ans=0;
while(b){if(b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;}
return b;
}
ll Hash(string s){
ll ans1=0,ans2=0;
For(ch,s){
ans1+=(ans1*ans1%mod+Pow(ch,ch,mod1))%mod1;
ans2+=(ans2*ans2%mod+Pow(ch,ch,mod2))%mod2;
}
ans1^=(ans1>>13);ans1^=(ans1<<4);ans1^=(ans1<<13);
ans2^=(ans2>>5);ans2^=(ans2<<7);ans2^=(ans2<<4);
return (ans1+ans2)%(ans1^ans2);
}
#endif
const int N=200005;
const int M=200005;
int n,m,k;
void init_(){
return;
}
void Main(int cases){
return;
}
/*
---INFORMATIONS---
TIME:<DATETIME>
PROBLEM:
CODE BY __CrossBow_EXE__ Luogu uid967841
CEXE好闪,拜谢CEXE。
*/
#define oneCase
signed main(int argc,char *argv[]){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
int T;
#ifdef oneCase
T=1;
#else
T=read();
#endif
init_();
up(i,1,T) Main(i);
return 0;
}
数据结构模板
大根堆,一条大根堆
int heap[10005],num=0;//大根堆
void in(int x){
heap[++num]=x;
int fa;
int son=num;
while(son/2){
fa=son/2;
if(heap[son]>heap[fa]) swap(heap[son],heap[fa]);
else break;
son=fa;
}
}
int out(){
int res=heap[1];
heap[1]=heap[num--];
int fa=1,son;
while(fa*2<=num){
son=fa*2;
if(son+1<=num&&heap[son]<heap[son+1]) son++;
if(heap[son]>heap[fa]) swap(heap[son],heap[fa]);
else break;
fa=son;
}
return res;
}
小根堆
int heap[10005],num=0;//小根堆
void in(int x){
heap[++num]=x;
int fa;
int son=num;
while(son/2){
fa=son/2;
if(heap[son]<heap[fa]) swap(heap[son],heap[fa]);
else break;
son=fa;
}
}
int out(){
int res=heap[1];
heap[1]=heap[num--];
int fa=1,son;
while(fa*2<=num){
son=fa*2;
if(son+1<=num&&heap[son]>heap[son+1]) son++;
if(heap[son]<heap[fa]) swap(heap[son],heap[fa]);
else break;
fa=son;
}
return res;
}
单调栈
for(int i=1;i<=n;i++){
while(!st.empty()&&a[st.top()]<a[i]) num[st.top()]=i,st.pop();
st.push(i);
}
单调队列(滑动窗口)
head=0,tail=-1;
for(int i=1;i<=n;i++){
while(head<=tail&&a[q[tail]]>=a[i]) tail--;//窗口最小值
q[++tail]=i;
while(q[head]<i-k+1) head++;
if(i>=k) cout<<a[q[head]]<<' ';
}
cout<<endl;
ST表
输入
for(int i=1;i<=n;i++){
cin>>a[i][0];
}
预处理
for(int j=1;j<20;j++){
for(int i=1;i<=n;i++){
a[i][j]=max(a[i][j-1],a[min(i+(1<<j-1),n)][j-1]);
}
}
查询
while(m--){
cin>>l>>r;
int k=log2(r-l+1);
cout<<max(a[l][k],a[r-(1<<k)+1][k])<<endl;
}
真神线段树
单点修改、求区间和
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const int N=1000005;
int n,m,op,x,y;
int a[N];
struct node{
int l,r,sum;//左右儿子 区间和
}tr[N<<2];//共4*n个线段树节点
void pushup(int u){//和向上传递
tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
//和=左边和+右边和
}
void build(int u,int l,int r){
tr[u].l=l,tr[u].r=r;
if(l==r){//如果到了叶子区间
tr[u].sum=a[l];//和直接就是a[l]
return;
}
int mid=(l+r)>>1;
build(u<<1,l,mid);//建左边
build(u<<1|1,mid+1,r);//建右边
pushup(u);//传递上去
}
void modify(int u,int x,int k){
if(tr[u].l==tr[u].r){//是叶子节点
tr[u].sum+=k;//直接修改就行
return;
}
//tr[u].l - tr[u].r
int mid=(tr[u].l+tr[u].r)>>1;
//tr[u].l - mid,mid+1 - tr[u].r
if(x<=mid) modify(u<<1,x,k);//改左边
else modify(u<<1|1,x,k);//改右边
pushup(u);
}
int ask(int u,int l,int r){
if(tr[u].l>=l&&tr[u].r<=r) return tr[u].sum;//包含在区间内,直接输出和
int mid=(tr[u].l+tr[u].r)>>1,sum=0;
if(mid>=l) sum+=ask(u<<1,l,r);//加左边
if(mid<r) sum+=ask(u<<1|1,l,r);//加右边
return sum;
}
int main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
build(1,1,n);//从1建到n
while(m--){
cin>>op;
if(op==1){
cin>>x>>y;
modify(1,x,y);//a[x]+=y
}else{
cin>>x>>y;
cout<<ask(1,x,y)<<endl;
}
}
return 0;
}
区间修改、求区间和
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define int long long
using namespace std;
const int N=100005;
int a[N];
int n,m,op,x,y,k;
struct node{
int l,r,sum,lazy;
}tr[N<<2];
void pushup(int u){
tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
void pushdown(int u){
if(tr[u].lazy){//有懒标记才pushdown
tr[u<<1].sum+=(tr[u<<1].r-tr[u<<1].l+1)*tr[u].lazy;//区间和增加(区间元素个数)个懒标记
tr[u<<1|1].sum+=(tr[u<<1|1].r-tr[u<<1|1].l+1)*tr[u].lazy;
tr[u<<1].lazy+=tr[u].lazy;//把懒标记传递给左右孩子
tr[u<<1|1].lazy+=tr[u].lazy;
tr[u].lazy=0;//清空懒标记
}
}
void build(int u,int l,int r){
tr[u].l=l,tr[u].r=r;
if(l==r){
tr[u].sum=a[l];
tr[u].lazy=0;//懒标记初始化
return;
}
int mid=(l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
void modify(int u,int l,int r,int val){
if(tr[u].l>=l&&tr[u].r<=r){
tr[u].sum+=val*(tr[u].r-tr[u].l+1);//需要加很多个val
tr[u].lazy+=val;//懒标记一下,标记加上过val
return;
}
pushdown(u);//懒标记下传
int mid=(tr[u].l+tr[u].r)>>1;
if(mid>=l) modify(u<<1,l,r,val);
if(mid<r) modify(u<<1|1,l,r,val);
pushup(u);
}
int ask(int u,int l,int r){
if(tr[u].l>=l&&tr[u].r<=r){
return tr[u].sum;
}
pushdown(u);
int mid=(tr[u].l+tr[u].r)>>1,sum=0;
if(mid>=l) sum+=ask(u<<1,l,r);
if(mid<r) sum+=ask(u<<1|1,l,r);
return sum;
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
build(1,1,n);
while(m--){
cin>>op;
if(op==1){
cin>>x>>y>>k;
modify(1,x,y,k);
}else{
cin>>x>>y;
cout<<ask(1,x,y)<<endl;
}
}
return 0;
}
树状数组
单点修改区间查询
void add(int x,int k){//将a[x]加上k
for(;x<N;x+=x&-x){
tr[x]+=k;
}
}
int ask(int x){//求1-x的和
int ans=0;
for(;x;x-=x&-x){
ans+=tr[x];
}
return ans;
}
区间修改单点查询
不使用树状数组维护 \(a_i\),而是维护差分数组 \(cf_i=a_i-a_{i-1}\)。
修改:
cin>>x>>y>>k;
add(x,k);
add(y+1,-k);
查询:
cin>>x;
cout<<ask(x)<<endl;
区间修改区间查询
开两个树状数组:int tr[N][2];
修改、查询:
void add(int x,int k,int op){
for(;x<N;x+=x&-x){
tr[x][op]+=k;
}
}
int ask(int x,int op){
int ans=0;
for(;x;x-=x&-x){
ans+=tr[x][op];
}
return ans;
}
初始化:
for(int i=1;i<=n;i++){
cin>>a[i];
add(i,a[i]-a[i-1],0);
add(i,i*(a[i]-a[i-1]),1);
}
查询:
for(int i=1,op,x,y,k;i<=m;i++){
cin>>op>>x>>y;
if(op==1){
cin>>k;
add(x,k,0);
add(y+1,-k,0);
add(x,x*k,1);
add(y+1,-(y+1)*k,1);
}else{
cout<<solve(y)-solve(x-1)<<endl;
}
}
并查集
【优化】路径压缩
int find(int x){//查
if(f[x]==x) return x;
else return f[x]=find(f[x]);
}
void merge(int x,int y){//并
int a=find(x),b=find(y);
if(a!=b) f[a]=b;
}
【优化】启发式合并
int f[N],siz[N];
int find(int x){
if(f[x]==x) return x;
return f[x]=find(f[x]);
}
void merge(int x,int y){
int a=find(x),b=find(y);
// if(a!=b) f[a]=b;
if(a==b) return;
if(siz[a]>siz[b]){
f[b]=a;
siz[a]+=siz[b];
}else{
f[a]=b;
siz[b]+=siz[a];
}
}
//主函数中for(int i=1;i<=N;i++) siz[i]=1;
【优化】随机合并
//#include<cstdlib>
int find(int x){
if(f[x]==x) return x;
return f[x]=find(f[x]);
}
void merge(int x,int y){
int a=find(x),b=find(y);
if(a==b) return;
if(rand()&1) /*rand()%2==0*/f[a]=b;
else f[b]=a;
}
平衡树
Splay
int getwh(int x){return ch[f[x]][1]==x;}
void pushup(int x){
sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+cnt[x];
}
void rotate(int x){//转
int y=f[x],z=f[y],k=getwh(x);//y是爸爸,z是爷爷
f[x]=z;
ch[z][getwh(y)]=x;
f[ch[x][k^1]]=y;
ch[y][k]=ch[x][k^1];
f[y]=x;
ch[x][k^1]=y;
pushup(y);
pushup(x);
}
void splay(int x,int tar){//把x旋转到tar的儿子
if(x==-1) return;
while(f[x]!=tar){
int y=f[x],z=f[y];
if(z!=tar){
if(getwh(y)==getwh(x)) rotate(y);//共线
else rotate(x);
}
rotate(x);
}
if(tar==0) root=x;
}
void insert(int v){//插入v
int x=root,y=0;
while(x&&v!=a[x]){//看看v要插入到哪里
y=x;
x=ch[x][v>a[x]];
}
if(x) cnt[x]++,sum[x]++;//有v这个节点
else{//没有
x=++tot;
if(y) ch[y][v>a[y]]=x;//有父亲
f[x]=y;
sum[x]=cnt[x]=1;//初始化子树大小、值的个数
a[x]=v;
}
splay(x,0);
}
void find(int v){//找到v并旋转到根节点
int x=root;
if(!x) return;//根节点
while(ch[x][v>a[x]]&&v!=a[x]) x=ch[x][v>a[x]];//有儿子就一直往下找
splay(x,0);//转到根
}
int nxt(int v,int f){
find(v);//旋到根
int x=root;
if(a[x]>v&&f==1) return x;//后继
if(a[x]<v&&f==0) return x;//前驱
x=ch[x][f];//走一步
while(ch[x][f^1]) x=ch[x][f^1];//一直往下,反方向走
return x;
}
void erase(int v){
int pre=nxt(v,0),next=nxt(v,1);//找前驱和后继
splay(pre,0);splay(next,pre);
int x=ch[next][0];//v一定到了next左边
if(cnt[x]>1){//v这个值不止一个
cnt[x]--;
pushup(x);
splay(x,0);
}else{
ch[next][0]=0;//删掉后继的左儿子
f[x]=0;
}
}
int getrank(int v){//v的排名,有多少个数小于v
int x=root,rank=0;
while(x){
if(a[x]>v) x=ch[x][0];//大了,往左走
else if(a[x]==v){//找到了
rank+=sum[ch[x][0]];
tag=x;
return rank;
}
else{
rank+=sum[ch[x][0]]+cnt[x];
x=ch[x][1];//小了,往右走
}
}
return rank;
}
int kth(int k){
int x=root;
while(1){
if(sum[ch[x][0]]>=k) x=ch[x][0];//左边有至少k个,一定在左边
else if(sum[ch[x][0]]+cnt[x]>=k){//左边不够,加上自己够了,一定是自己
tag=x;
return a[x];
}
else{//在右边,往右走
k-=sum[ch[x][0]]+cnt[x];
x=ch[x][1];
}
}
}
FHQ-Treap
mt19937 rd(time(0));
struct node{
int l,r;
int val,key;//key随机分配
int sum;
}tr[N];
void pushup(int u){
tr[u].sum=tr[ls].sum+tr[rs].sum+1;
}
void split(int u,int val,int &x,int &y){//分裂
if(!u){
x=y=0;//到了底部
return;
}
if(tr[u].val<=val){//值小了
x=u;
split(rs,val,rs,y);//往右分裂
}else{//值大了
y=u;
split(ls,val,x,ls);//往左分裂
}
pushup(u);
}
int merge(int x,int y){//合并
if(!x||!y) return x+y;//一上一下,直接合并
if(tr[x].key>tr[y].key){//x大,y当x儿子
tr[x].r=merge(tr[x].r,y);
pushup(x);
return x;
}else{//y大,x当y儿子
tr[y].l=merge(x,tr[y].l);
pushup(y);
return y;
}
}
int new_node(int val){
tr[++cnt]=(node){NULL,NULL,val,rd(),1};//无左右儿子,key随机生成
return cnt;
}
void insert(int val){
split(root,val,x,y);//从val开始分裂
root=merge(merge(x,new_node(val)),y);//合并两次
}
void erase(int val){
split(root,val,x,z);//x<=val z>val
split(x,val-1,x,y);//x<val y==val
y=merge(tr[y].l,tr[y].r);
root=merge(merge(x,y),z);
}
int getrank(int val){
x=root;
int rank=0;
while(x){
if(tr[x].val<val) rank+=tr[tr[x].l].sum+1,x=tr[x].r;//往右
else x=tr[x].l;//往左
}
return rank;
}
int kth(int k){
x=root;
while(x){
if(tr[tr[x].l].sum>=k) x=tr[x].l;//左子树够了,往左跳
else if(tr[tr[x].l].sum+1>=k) return tr[x].val;//正好是自己
else{//左边不够
k-=tr[tr[x].l].sum+1;
x=tr[x].r;//往右跳
}
}
}
int pre(int val){
split(root,val-1,x,y);//往左跳一下
int u=x;
while(tr[u].r) u=tr[u].r;//一直往右跳
merge(x,y);
return tr[u].val;
}
int nxt(int val){
split(root,val,x,y);//往左跳一下
int u=y;
while(tr[u].l) u=tr[u].l;//一直往右跳
merge(x,y);
return tr[u].val;
}
文艺平衡树
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define l(x) (tr[x].l)
#define r(x) (tr[x].r)
#define f(x) (tr[x].f)
#define val(x) (tr[x].val)
#define sum(x) (tr[x].sum)
#define cnt(x) (tr[x].cnt)
#define lazy(x) (tr[x].lazy)
using namespace std;
int n,m;
const int N=100005;
struct node{
int l,r,f;
int val;
int sum;
int lazy;//懒标记
}tr[N];
int root,cnt=0;
void pushup(int u){
sum(u)=sum(l(u))+sum(r(u))+1;
}
void pushdown(int u){//旋转子树
if(lazy(u)){
swap(l(u),r(u));
lazy(l(u))^=1;
lazy(r(u))^=1;
lazy(u)=0;
}
}
int getwh(int x){
return r(f(x))==x;
}
void rotate(int x){
int y=f(x),z=f(y),k=getwh(x);
f(x)=z;
if(getwh(y)) r(z)=x;
else l(z)=x;
if(k){
f(l(x))=y;
r(y)=l(x);
f(y)=x;
l(x)=y;
}else{
f(r(x))=y;
l(y)=r(x);
f(y)=x;
r(x)=y;
}
pushup(y);
pushup(x);
}
void splay(int x,int tar){
while(f(x)!=tar){
int y=f(x),z=f(y);
if(z!=tar){
if(getwh(y)==getwh(x)) rotate(y);
else rotate(x);
}
rotate(x);
}
if(!tar) root=x;
}
int build(int l,int r,int f){//建树
if(l>r) return 0;
int mid=(l+r)>>1,val=mid-1,tmp=++cnt;
if(val==0) val=-2e9;
else if(val==n+1) val=2e9;
//建左右
tr[tmp]=(node){build(l,mid-1,tmp),build(mid+1,r,tmp),f,val,0,0};
pushup(tmp);
return tmp;
}
int kth(int k){//第几大,和之前没有区别
int x=root;
while(x){
pushdown(x);
if(sum(l(x))>=k) x=l(x);
else if(sum(l(x))+1>=k) return x;
else{
k-=sum(l(x))+1;
x=r(x);
}
}
}
void print(int x){
pushdown(x);
if(l(x)) print(l(x));
if(abs(val(x))!=2e9) cout<<val(x)<<' ';
if(r(x)) print(r(x));
}
signed main(int argc,char *argv[]){
ios::sync_with_stdio(NULL);
cin.tie(0),cout.tie(0);
cin>>n>>m;
root=build(1,n+2,0);
for(int i=1,l,r,pre,nxt;i<=m;i++){
cin>>l>>r;
l++,r++;
pre=kth(l-1),nxt=kth(r+1);
splay(pre,0);
splay(nxt,pre);
lazy(l(r(root)))^=1;
}
print(root);
return 0;
}
二分
二分答案万能模板
bool check(int x){
//TODO
}
int find(){
int l=1,r=1e9,opt=-1;
while(l<=r){
int mid=(l+r)>>1;
if(opt==mid) break;
opt=mid;
if(check(mid)) r=mid;
else l=mid;
}
if(check(min(l,r))) return min(l,r);
else return max(l,r);
}
二分,但是实数
const double eps=1e-6;//eps,误差值
while(r-l>eps){
double mid=(l+r)/2;
if(check(mid)) r=mid;
else l=mid;
}
离散化
创建离散化 vector
vector<int> num;
求 \(a_i\) 离散化后的值
int get(int x){
return lower_bound(num.begin(),num.end(),x)-num.begin();
}
离散化
sort(num.begin(),num.end());
num.erase(unique(num.begin(),num.end()),num.end());
数学 & 数论
中缀表达式转表达式树
long long dfs(int l,int r){
int x=0,y=0,z=0;
for(int i=l;i<=r;i++){
if(a[i]=='(') x++;
else if(a[i]==')') x--;
else{
if(x==0&&(a[i]<'0'||a[i]>'9')){
if(a[i]=='*'||a[i]=='/') y=i;
else z=i;
}
}
}
if(z){
tree[z].l=dfs(l,z-1);
tree[z].r=dfs(z+1,r);
return z;
}
if(y){
tree[y].l=dfs(l,y-1);
tree[y].r=dfs(y+1,r);
return y;
}
if(a[l]=='('&&a[r]==')') return dfs(l+1,r-1);
int k=0;
for(int i=l;i<=r;i++){
k=k*10+a[i]-'0';
}
tree[l].val=k;
return l;
}
void pre(int x){//遍历
if(tree[x].l) pre(tree[x].l);
if(tree[x].r) pre(tree[x].r);
c[++cnt]=x;
}
gcd
int gcd(int x,int y){
if(y==0) return x;
else return gcd(y,x%y);
}
exgcd
ll exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x=1,y=0;
return a;
}
ll d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
快速幂
正常版
ll qpow(ll a,ll b,ll m){
ll ans=1;
while(b){
if(b&1) ans=ans*a%m;//b%2==1
a=a*a%m;
b>>=1;//b/=2
}
return ans;
}
压行版
ll Pow(ll a,ll b,ll mod){
ll ans=1;
for(;b;a=a*a%mod,b>>=1){
if(b&1) ans=ans*a%mod;
}
return ans;
}
素数筛法
埃氏筛法
void get_all_prime() {
int cnt=0;
prime[0]=1;
prime[1]=1;
for(int i=2; i<=40000; i++) {
if(!prime[i]) {
for(int j=2*i; j<=40000; j+=i) {
prime[j]=0;
}
}
}
}
欧拉筛 & 线性筛
for(int i=2;i<=n;i++){
if(!vis[i]) p.push_back(i);//如果是质数,就把它放进质数数组里
for(int j=0;j<p.size();j++){//遍历所有质数
if(i*p[j]>n) break;//边界情况
vis[i*p[j]]=1;//标记合数
if(i%p[j]==0) break;//能整除就退出,线性筛特点
}
}
素数判定
正常判
bool prime(int x){
if(x==0||x==1) return 0;
if(x==2) return 1;
for(int i=2;i*i<=x;i++){
if(x%i==0) return 0;
}
return 1;
}
Miller-Rabin
int p[12]={2,3,5,7,11,13,17,19,23,29,31,37};
ll Pow(ll a,ll b,ll p){//快速幂
ll ans=1;
while(b){
if(b&1) ans=ans*a%p;
a=a*a%p;
b>>=1;
}
return ans;
}
ll Mul(ll a,ll b,ll p){//龟速乘
a%=p,b%=p;
ll k=(long double)a*b/p;
long double ans=a*b-k*p;
return (ll)(ans+p)%p;
}
bool miller_rabin(ll x){
if(x==0||x==1) return 0;
if(x==2) return 1;
if(x%2==0) return 0;
ll s=x-1,t=0;
while(s%2==0) t++,s>>=1;
for(int i=0;i<12&&p[i]<x;i++){
if(x%p[i]==0) return 0;
ll pre=Pow(p[i],s,x),tmp=pre;
for(int j=1;j<=t;j++){
tmp=Mul(tmp,tmp,x);
if(tmp==1&&pre!=1&&pre!=x-1) return 0;
pre=tmp;
}
if(tmp!=1) return 0;
}
return 1;
}
逆元
给定 \(n,p\) 求 \(1\sim n\) 中所有整数在模 \(p\) 意义下的乘法逆元。
\(a\) 模 \(p\) 的乘法逆元定义为 \(ax\equiv1\pmod p\) 的解。
费马小定理
条件:\(p\) 为质数。
Pow(n,p-2,p);//快速幂
扩展欧几里得
条件:无。【万能钥匙】
exgcd(n,p,x,y);//扩展欧几里得模板
//答案:(x%p+p)%p
递推求逆元
inv[1]=1;
for(ll i=2;i<=n;i++){
inv[i]=(p-p/i)*inv[p%i]%p;
}
卢卡斯定理
int Lucas(int n,int m){
if(m==0) return 1;
else return (Lucas(n/p,m/p)%p*C(n%p,m%p)%p)%p;
}
多项式
DFT
const double PI=acos(-1);
const int N=100005;
struct num{//复数类
double x,y;//x+yi
num(double xx=0,double yy=0){x=xx,y=yy;}
num operator +(num const &B) const{return num(x+B.x,y+B.y);}
num operator -(num const &B) const{return num(x-B.x,y-B.y);}
num operator *(num const &B) const{return num(x*B.x-y*B.y,x*B.y+y*B.x);}
//除法没用
}f[N<<1],tmp[N<<1];
void dft(num *f,int len){
if(len==1) return;//边界条件
num *f0=f,*f1=f+len/2;
for(int i=0;i<len;i++) tmp[i]=f[i];//缓存
for(int i=0;i<(len>>1);i++){//分奇偶打乱
f0[i]=tmp[i<<1];
f1[i]=tmp[i<<1|1];
}
//分治
dft(f0,len>>1);
dft(f1,len>>1);
num t(cos(2*PI/len),sin(2*PI/len)),buf(1,0);
for(int i=0;i<(len>>1);i++){
tmp[i]=f0[i]+buf*f1[i];
tmp[i+(len>>1)]=f0[i]-buf*f1[i];
buf=buf*t;//旋转
}
for(int i=0;i<len;i++) f[i]=tmp[i];//放回
}
FFT
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
int n,m;
const double PI=acos(-1);
const int N=2000005;
struct num{
double x,y;//x+yi
num(double xx=0,double yy=0){x=xx,y=yy;}
num operator +(num const &B) const{return num(x+B.x,y+B.y);}
num operator -(num const &B) const{return num(x-B.x,y-B.y);}
num operator *(num const &B) const{return num(x*B.x-y*B.y,x*B.y+y*B.x);}
//除法没用
}f[N<<1],g[N<<1],tmp[N<<1];
void fft(num *f,int len,int type){
if(len==1) return;//边界条件
num *f0=f,*f1=f+(len>>1);
for(int i=0;i<len;i++) tmp[i]=f[i];//缓存
for(int i=0;i<(len>>1);i++){//分奇偶打乱
f0[i]=tmp[i<<1];
f1[i]=tmp[i<<1|1];
}
//分治
fft(f0,len>>1,type);
fft(f1,len>>1,type);
num t(cos(2*PI/len),type*sin(2*PI/len)),buf(1,0);
for(int i=0;i<(len>>1);i++){
tmp[i]=f0[i]+buf*f1[i];
tmp[i+(len>>1)]=f0[i]-buf*f1[i];
buf=buf*t;//旋转
}
for(int i=0;i<len;i++) f[i]=tmp[i];//放回
}
int ans[N];
signed main(int argc,char *argv[]){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(NULL);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=0;i<=n;i++) cin>>f[i].x;
for(int i=0;i<=m;i++) cin>>g[i].x;
int lim=1;
for(;lim<=n+m;lim<<=1);
fft(f,lim,1);fft(g,lim,1);
for(int i=0;i<=lim;i++){
f[i]=f[i]*g[i];
}
fft(f,lim,-1);
for(int i=0;i<=lim;i++) ans[i]+=int(f[i].x/lim+0.5);
for(int i=0;i<=n+m;i++) cout<<ans[i]<<' ';
cout<<endl;
return 0;
}
FFT 非递归
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
int n,m;
const double PI=acos(-1);
const int N=2000005;
int r[N<<1];
struct num{
double x,y;//x+yi
num(double xx=0,double yy=0){x=xx,y=yy;}
num operator +(num const &B) const{return num(x+B.x,y+B.y);}
num operator -(num const &B) const{return num(x-B.x,y-B.y);}
num operator *(num const &B) const{return num(x*B.x-y*B.y,x*B.y+y*B.x);}
//除法没用
}a[N<<1];
void fft(num *f,int lim,int type){
for(int i=0;i<lim;i++){//重新排列元素
if(i<r[i]) swap(f[i],f[r[i]]);
}
for(int mid=1;mid<lim;mid<<=1){//当前区间长度
num t(cos(PI/mid),type*sin(PI/mid));//单位根初始化
for(int len=mid<<1,j=0;j<lim;j+=len){
num w(1,0);//平躺单位根
for(int i=0;i<mid;i++,w=w*t){//旋转
num x=f[i+j],y=w*f[i+j+mid];
f[i+j]=x+y;
f[i+j+mid]=x-y;
}
}
}
if(type==-1){
for(int i=0;i<lim;i++){
a[i].x/=lim;
a[i].y/=lim;
}
}
}
int ans[N];
int L;
signed main(int argc,char *argv[]){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(NULL);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=0;i<=n;i++) cin>>a[i].x;
for(int i=0;i<=m;i++) cin>>a[i].y;
int lim=1;
for(;lim<=n+m;lim<<=1,L++);
for(int i=0;i<=lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
fft(a,lim,1);
for(int i=0;i<=lim;i++) a[i]=a[i]*a[i];
fft(a,lim,-1);
for(int i=0;i<=n+m;i++){
cout<<int(a[i].y/2+0.5)<<' ';
}
return 0;
}
FFT 三步变两步
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
int n,m;
const double PI=acos(-1);
const int N=2000005;
int r[N<<1];
struct num{
double x,y;//x+yi
num(double xx=0,double yy=0){x=xx,y=yy;}
num operator +(num const &B) const{return num(x+B.x,y+B.y);}
num operator -(num const &B) const{return num(x-B.x,y-B.y);}
num operator *(num const &B) const{return num(x*B.x-y*B.y,x*B.y+y*B.x);}
//除法没用
}a[N<<1];
void fft(num *f,int lim,int type){
for(int i=0;i<lim;i++){//重新排列元素
if(i<r[i]) swap(f[i],f[r[i]]);
}
for(int mid=1;mid<lim;mid<<=1){//当前区间长度
num t(cos(PI/mid),type*sin(PI/mid));//单位根初始化
for(int len=mid<<1,j=0;j<lim;j+=len){
num w(1,0);//平躺单位根
for(int i=0;i<mid;i++,w=w*t){//旋转
num x=f[i+j],y=w*f[i+j+mid];
f[i+j]=x+y;
f[i+j+mid]=x-y;
}
}
}
if(type==-1){
for(int i=0;i<lim;i++){
a[i].x/=lim;
a[i].y/=lim;
}
}
}
int ans[N];
int L;
signed main(int argc,char *argv[]){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(NULL);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=0;i<=n;i++) cin>>a[i].x;
for(int i=0;i<=m;i++) cin>>a[i].y;
int lim=1;
for(;lim<=n+m;lim<<=1,L++);
for(int i=0;i<=lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
fft(a,lim,1);
for(int i=0;i<=lim;i++) a[i]=a[i]*a[i];
fft(a,lim,-1);
for(int i=0;i<=n+m;i++){
cout<<int(a[i].y/2+0.5)<<' ';
}
return 0;
}
NTT
void dtt(ll *f,int lim,int type){
for(int i=0;i<lim;i++){
if(i<r[i]) swap(f[i],f[r[i]]);
}
for(int mid=1;mid<lim;mid<<=1){
//g原根,gi原根逆元
ll t=Pow(type==1?g:gi,(mod-1)/(mid<<1));
for(int j=0;j<lim;j+=(mid<<1)){
ll w=1;
for(int i=0;i<mid;i++,w=(w*t)%mod){
int x=f[i+j],y=w*f[i+j+mid]%mod;
f[i+j]=(x+y)%mod;
f[i+j+mid]=(x-y+mod)%mod;
}
}
}
}
BSGS
//求最小的x,使得a^x%p==b%p,也就是求离散对数log_a b
ll BSGS(ll a,ll b,ll p){
a%=p,b%=p;
if(b==1) return 0;//x=0
unordered_map<int,int> mp;
ll m=ceil(sqrt(p)),t=b;
mp[t]=0;
for(int i=1;i<m;i++){
t=t*a%p;
mp[t]=i;
}
ll s=Pow(a,m,p);
t=1;
for(int i=1;i<=m;i++){
t=t*s%p;
if(mp.count(t)>0) return i*m-mp[t];
}
return -1;
}
矩阵
const int N=3;
struct mtx{
int n,m;
ll a[N+5][N+5];
mtx(){memset(a,0,sizeof(a));}
friend mtx operator *(mtx a,mtx b){//a.m==b.n
mtx ans;
ans.n=a.n;ans.m=b.m;
up(i,1,a.n){
up(j,1,b.m){
up(k,1,a.m){
ans.a[i][j]+=(ll)a.a[i][k]*b.a[k][j];
ans.a[i][j]%=mod;
}
}
}
return ans;
}
};
mtx Pow(mtx a,int k){//a.n==a.m
mtx ans;
ans.n=ans.m=a.n;
up(i,1,ans.n) ans.a[i][i]=1;
while(k){
if(k&1) ans=ans*a;
a=a*a;
k>>=1;
}
return ans;
}
加快程序运行速度程序
快读&写
快读
inline int read() {
int x=0,f=1;
char c=getchar();//读入第一个字符
while(c<'0'||c>'9') {//如果这个字符不是数字
if(c=='-')f=-1;//那么只能是减号,也就是负数标记
c=getchar();//继续读入
}
while(c>='0'&&c<='9') {
x=(x<<3)+(x<<1)+c-48;//将字符转换为数字
c=getchar();//继续读入
}
return x*f;//返回这个数字
}
快写
void write(int x) {
if (x < 0) {
putchar('-');//如果这个数小于0,说明它是负数,先输出负数标记
x = -x;//将这个数变成负数的它
}
if (x > 9) {
write(x / 10);//递归式
}
putchar(x % 10 + '0');//输出数字
return ;
}
tie(0)
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
超级快读
https://www.luogu.me/paste/ilt13pl4
namespace Fast_I{
char *_Buf,*_Start_ptr,*_End_ptr;
streambuf *inbuf;
unsigned int Size;
bool _Ok;
struct Fast_Istream{
operator bool(){return _Ok;}
Fast_Istream(streambuf *in,unsigned int Sz){
_Ok=1;
Fast_I::Size=Sz;
inbuf=in;
_Start_ptr=_End_ptr=_Buf=new char[Sz];
}
Fast_Istream(const char *in,unsigned int Sz){
_Ok=1;
Fast_I::Size=Sz;
rdbuf(in);
_Start_ptr=_End_ptr=_Buf=new char[Sz];
}
Fast_Istream(unsigned int Sz){
_Ok=1;
Fast_I::Size=Sz;
_Start_ptr=_End_ptr=_Buf=new char[Sz];
}
void rdbuf(const char *File){
static ifstream __In__(File);
rdbuf(__In__.rdbuf());
}
void Get_Char(char &_Val){
if(_Start_ptr==_End_ptr){
_Start_ptr=_Buf;
_End_ptr=_Buf+inbuf->sgetn(_Buf,Size);
}
if(_Start_ptr==_End_ptr){
_Val=-1;
_Ok=0;
}else _Val=*_Start_ptr++;
}
Fast_Istream &operator>>(char &_Val){
if(_Ok){
Get_Char(_Val);
while(_Val==32||_Val==10||_Val==13||_Val==8||_Val==9||_Val==7||_Val==12||_Val==11) Get_Char(_Val);
}
return *this;
}
Fast_Istream &operator>>(char *_Val){
if(_Ok){
Get_Char(*_Val);
while(*_Val==32||*_Val==10||*_Val==13||*_Val==8||*_Val==9||*_Val==7||*_Val==12||*_Val==11) Get_Char(*_Val);
while(*_Val!=32&&*_Val!=10&&*_Val&&*_Val!=-1&&*_Val!=9 &&*_Val!=11&&*_Val!=12&&~*_Val) Get_Char(*++_Val);
*_Val=0;
--_Start_ptr;
}
return *this;
}
Fast_Istream &operator>>(string &_Val){
if(_Ok){
char c;
Get_Char(c);
while(c==32||c==10||c==13||c==8||c==9||c==7||c==12||c==11) Get_Char(c);
for(_Val.clear();c!=32&&c!=10&&c&&c!=-1&&c!=9&&c!=11&&c!=12&&~c;Get_Char(c)) _Val.push_back(c);
--_Start_ptr;
}
return *this;
}
template <typename Typex>
void Get_Int(Typex &_Val){
if(_Ok){
char ch;
bool _F=0;
for(Get_Char(ch);(ch<48||ch>57)&&~ch;Get_Char(ch)) _F=ch==45;
for(_Val=0;ch>47&&ch<58&&~ch;Get_Char(ch)) _Val=_Val*10+(ch^48);
if(_F) _Val=~_Val+1;
--_Start_ptr;
}
}
template <typename Typex>
void Get_Unsigned(Typex &_Val){
if(_Ok){
char ch;
Get_Char(ch);
while((ch<48||ch>57)&&~ch) Get_Char(ch);
for(_Val=0;ch>47&&ch<58&&~ch;Get_Char(ch)) _Val=_Val*10+(ch^48);
--_Start_ptr;
}
}
template <typename Typex>
void Get_Double(Typex &_Val){
if(_Ok){
char ch;
bool _F=0;
for(Get_Char(ch);(ch<48||ch>57)&&~ch;Get_Char(ch)) _F=ch==45;
for(_Val=0;ch>47&&ch<58&&~ch;Get_Char(ch)) _Val=_Val*10+(ch^48);
if(ch==46){
unsigned long long _Pow=1;
for(Get_Char(ch);ch>47&&ch<58&&~ch;Get_Char(ch)) _Val+=Typex((ch^48)*1.0/(_Pow*=10));
}
if(_F) _Val=-_Val;
--_Start_ptr;
}
}
Fast_Istream &operator>>(bool &_Val){
if(_Ok){
char ch;
Get_Char(ch);
while(ch==32||ch==10||ch==13||ch==8||ch==9||ch==7||ch==12||ch==11) Get_Char(ch);
while(ch!=32&&ch!=10&&ch&&~ch&&ch!=9&&ch!=11&&ch!=12&&~ch){
_Val|=ch!=48;
Get_Char(ch);
}
--_Start_ptr;
}
return *this;
}
Fast_Istream &operator>>(short &_Val){
Get_Int(_Val);
return *this;
}
Fast_Istream &operator>>(int &_Val){
Get_Int(_Val);
return *this;
}
Fast_Istream &operator>>(long &_Val){
Get_Int(_Val);
return *this;
}
Fast_Istream &operator>>(long long &_Val){
Get_Int(_Val);
return *this;
}
Fast_Istream &operator>>(unsigned short &_Val){
Get_Unsigned(_Val);
return *this;
}
Fast_Istream &operator>>(unsigned int &_Val){
Get_Unsigned(_Val);
return *this;
}
Fast_Istream &operator>>(unsigned long &_Val){
Get_Unsigned(_Val);
return *this;
}
Fast_Istream &operator>>(unsigned long long &_Val){
Get_Unsigned(_Val);
return *this;
}
Fast_Istream &operator>>(float &_Val){
Get_Double(_Val);
return *this;
}
Fast_Istream &operator>>(double &_Val){
Get_Double(_Val);
return *this;
}
Fast_Istream &operator>>(long double &_Val){
Get_Double(_Val);
return *this;
}
template <typename Typex,typename... More>
void operator()(Typex &_Val,More &... _More){
*this>>_Val;
operator()(_More...);
}
void pop(){
char ch;
Get_Char(ch);
}
char peek(){
if(_Start_ptr==_End_ptr){
_Start_ptr=_Buf;
_End_ptr=_Buf+inbuf->sgetn(_Buf,Size);
}
if(_Start_ptr==_End_ptr){
_Ok=0;
return -1;
}else return *_Start_ptr;
}
template <typename Typex>
void operator()(Typex &_Val){*this>>_Val;}
template <typename Typex,typename...More>
streambuf *rdbuf(){return inbuf;}
void rdbuf(streambuf *_inbuf){inbuf=_inbuf;}
Fast_Istream getline(string &s,char _End='\n'){
if(_Ok){
char c;
Get_Char(c);
while((c==32||c==10||c==13||c==8||c==9||c==7||c==12||c==11||c==-1)&&c!=_End) Get_Char(c);
for(s.clear();c!=_End&&~c;Get_Char(c)) s.push_back(c);
--_Start_ptr;
}
return *this;
}
};
}
//快写
namespace Fast_O{
string buf;
streambuf *outbuf;
int _M_precision=6;
struct Fast_Ostream{
Fast_Ostream(streambuf *out,unsigned int Size){
buf.reserve(Size);
outbuf=out;
}
Fast_Ostream(std::streambuf* out){outbuf=out;}
Fast_Ostream(const char *File,unsigned int Size){
buf.reserve(Size);
rdbuf(File);
}
void rdbuf(const char *File){
static ofstream __Out__(File);
rdbuf(__Out__.rdbuf());
}
Fast_Ostream(unsigned int Size){buf.reserve(Size);}
void flush(){
outbuf->sputn(buf.data(),buf.size());
buf.clear();
}
~Fast_Ostream(){flush();}
void endl(){buf.push_back('\n');}
Fast_Ostream &operator<<(char _Val){
buf.push_back(_Val);
return *this;
}
Fast_Ostream &operator<<(const char *_Val){
while(*_Val) buf.push_back(*_Val++);
return *this;
}
Fast_Ostream &operator<<(const string &_Val){
buf+=_Val;
return *this;
}
template <typename Typex>
void Put_Unsigned(Typex _Val){
char *_Stack=(char *)malloc(sizeof(Typex)*3);
unsigned S_top=0;
while(_Val){
_Stack[++S_top]=(_Val%10)^48;
_Val/=10;
}
if(!S_top) buf.push_back('0');
while(S_top) buf.push_back(_Stack[S_top--]);
free(_Stack);
}
template <typename Typex>
void Put_Int(Typex _Val){
if(_Val<0){
buf.push_back('-');
Put_Unsigned(~_Val+1);
}else Put_Unsigned(_Val);
}
Fast_Ostream &operator<<(bool _Val){
buf.push_back(_Val?'1':'0');
return *this;
}
Fast_Ostream &operator<<(short _Val){
Put_Int(_Val);
return *this;
}
Fast_Ostream &operator<<(int _Val){
Put_Int(_Val);
return *this;
}
Fast_Ostream &operator<<(long _Val){
Put_Int(_Val);
return *this;
}
Fast_Ostream &operator<<(long long _Val){
Put_Int(_Val);
return *this;
}
Fast_Ostream &operator<<(unsigned short _Val){
Put_Unsigned(_Val);
return *this;
}
Fast_Ostream &operator<<(unsigned int _Val){
Put_Unsigned(_Val);
return *this;
}
Fast_Ostream &operator<<(unsigned long _Val){
Put_Unsigned(_Val);
return *this;
}
Fast_Ostream &operator<<(unsigned long long _Val){
Put_Unsigned(_Val);
return *this;
}
template <typename Typex>
void endl(const Typex &_Val){*this<<_Val<<'\n';}
template <typename Typex,typename... More>
void endl(const Typex &_Val,const More &... _More){
*this<<_Val;
endl(_More...);
}
template <typename Typex>
void operator()(const Typex &_Val){*this<<_Val;}
template <typename Typex,typename... More>
void operator()(const Typex &_Val,const More &... _More){
*this<<_Val;
operator()(_More...);
}
std::streambuf *rdbuf(){return outbuf;}
void rdbuf(std::streambuf *_outbuf){outbuf=_outbuf;}
};
}
namespace Fast_IO{
Fast_I::Fast_Istream fin(cin.rdbuf(),16777216);
Fast_O::Fast_Ostream fout(cout.rdbuf());
}
高精
太多了写不下,去看这里
排序
桶排序
for(int i=0;i<1000;i++){
int x;
cin>>x;
a[x]++;
}
for(int i=1000;i>=1;i--){
for(int j=1;j<=a[i];j++){
cout<<i<<' ';
}
}
冒泡排序
for(int i=1;i<n;i++){
for(int j=1;j<=n-i;j++){
if(a[j]>a[j+1]){
swap(a[j],a[j+1]);
}
}
}
选择排序
for(int i=1;i<=n-1;i++){
k=i;
for(int j=i+1;j<=n;j++){
if(a[k]>a[j]) k=j;
}
if(k!=i) swap(a[k],a[i]);
}
归并排序
void merge(int l,int r){
if(l==r) return;//边界
int mid=(l+r)>>1;//取mid将区间一分为二
merge(l,mid),merge(mid+1,r);//分而治之
int ans[MAXN];//建立一个临时数组当“罐子”
int i=l,j=mid+1,k=l;
for(;i<=mid&&j<=r&&k<=r;k++){
if(a[i]<=a[j]){//比较大小找出较小数
ans[k]=a[i];//把小的数往罐子里倒
i++;
}else{
ans[k]=a[j];
j++;
}
}
for(;i<=mid;i++) ans[k++]=a[i];//没把所有数都倒进去,接着倒
for(;j<=r;j++) ans[k++]=a[j];
for(int i=l;i<=r;i++){
a[i]=ans[i];//最后倒回去
}
}
快排
void Quicksort(int num[], int left, int right){
if (right <= left) return;
int i = left;
int j = right;
int key = num[left];
while (1){
//从左向右找比key大的值*/
while (num[i] <= key){
i++;
if (i == right) break;
}
//从右向左找比key小的值
while (num[j] >= key){
j--;
if (j == left) break;
}
if (i >= j) break;
//交换i,j对应的值
int temp = num[i];
num[i] = num[j];
num[j] = temp;
}
//中枢值与j对应值交换
num[left] = num[j];
num[j] = key;
Quicksort(num, left, j - 1);
Quicksort(num, j + 1, right);
}
sort排序
#include<bits/stdc++.h>
using namespace std;
int a[1005];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++){
cout<<a[i]<<' ';
}
return 0;
}
前缀和
一维前缀和
//从x加到y
sum[i]=sum[i-1]+a[i];
ans=sum[y]-sum[x-1];
假二维前缀和
//从(x1,y1)加到(x2,y2)
sum[i][j]=sum[i][j-1]+a[i][j];
for(int i=x1;i<=x2;i++){
ans+=sum[i][y2]-sum[i][y1-1];
}
二维前缀和
//从(x1,y1)加到(x2,y2)
sum[i][j]=a[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
ans=sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1];
假三维前缀和
//从(x,y,z)加到(x_,y_,z_)
sum[i][j][k]=sum[i][j-1][k]+sum[i][j][k-1]+a[i][j][k]-sum[i][j-1][k-1];
for(int i=x;i<=x_;i++){
ans+=sum[i][y_][z_]-sum[i][y-1][z_]-sum[i][y_][z-1]+sum[i][y-1][z-1];
}
实用程序
int 矩阵结构体
const int N=55;
struct matrix{
int n,m;
int a[N][N];
int sum[N][N];
int tmp[N][N];
int find(matrix where,int x,int y){
return where.a[x][y];
}
void input(){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
sum[i][j]=sum[i-1][j]+sum[i][j-1]+a[i][j]-sum[i-1][j-1];
}
}
}
void output(){
for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cout<<a[i][j]<<' ';}cout<<endl;}
}
void turn_left(){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
tmp[i][j]=a[j][4-i];
}
}
memcpy(a,tmp,sizeof(tmp));
}
void turn_right(){
for(int i=1;i<=3;i++) turn_left();
}
void flip_top(){
for(int i=1;i<=n/2;i++){
for(int j=1;j<=m;j++){
swap(a[i][j],a[n+1-i][j]);
}
}
}
void flip_left(){
for(int i=1;i<=n;i++){
for(int j=1;j<=m/2;j++){
swap(a[i][j],a[i][m+1-j]);
}
}
}
long long getSum(int x,int y,int x_,int y_){
long long ret;
ret=sum[x_][y_]-sum[x-1][y_]-sum[x_][y-1]+sum[x-1][y-1];
return ret;
}
};
更改剪切板
void Copy(string TempBin){
HGLOBAL hMemBin=NULL;
PCHAR LockBin=NULL;
OpenClipboard(NULL);
EmptyClipboard();
hMemBin=GlobalAlloc(GMEM_MOVEABLE,TempBin.size()+1);
LockBin=(PCHAR)GlobalLock(hMemBin);
RtlMoveMemory(LockBin,TempBin.c_str(),TempBin.size()+1);
GlobalUnlock(hMemBin);
LockBin=NULL;
SetClipboardData(CF_TEXT,hMemBin);
CloseClipboard();
}
树论
LCA
暴力跳
void dfs(int x,int from){//求深度
deep[x]=deep[from]+1;
f[x]=from;
for(int i=0;i<tree[x].size();i++){
int to=tree[x][i];
if(from==to) continue;
dfs(to,x);
}
}
int lca(int x,int y){
if(deep[x]>deep[y]) swap(x,y);
while(deep[x]>deep[y]) y=f[y];
if(x==y) return x;
while(x!=y) x=f[x],y=f[y];
return x;
}
倍增
void dfs(int x,int from){//求深度
deep[x]=deep[from]+1;
f[x][0]=from;
for(int i=1;i<20;i++){
f[x][i]=f[f[x][i-1]][i-1];
}
for(int i=0;i<tree[x].size();i++){
int to=tree[x][i];
if(from==to) continue;
dfs(to,x);
}
}
int lca(int x,int y){
if(deep[x]>deep[y]) swap(x,y);
for(int i=19;i>=0;i--){
if(deep[f[y][i]]>=deep[x]) y=f[y][i];
}
if(x==y) return x;
for(int i=19;i>=0;i--){
if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
}
return f[x][0];
}
pb_ds
头文件:
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>//用tree
#include<ext/pb_ds/hash_policy.hpp>//用hash
#include<ext/pb_ds/trie_policy.hpp>//用trie
#include<ext/pb_ds/priority_queue.hpp>//用priority_queue
using namespace __gnu_pbds;
hash_table
定义:
cc_hash_table<int,bool> mp;//稍快
gp_hash_table<int,bool> mp;
使用:
mp[a]=b;
mp.find(x);
平衡树
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#include<ext/pb_ds/trie_policy.hpp>
#include<ext/pb_ds/priority_queue.hpp>
#define ll long long
#define endl '\n'
using namespace std;
using namespace __gnu_pbds;
tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update> tr;
int n;
int cnt=0;
#define to(x,i) (((1ll*x)<<20)+i)//加密
#define bk(x) (x>>20)//解密
signed main(){
cin>>n;
for(int i=1,op,x;i<=n;i++){
cin>>op>>x;
if(op==1) tr.insert(to(x,++cnt));
if(op==2) tr.erase(tr.lower_bound(to(x,0)));//不必加上i
if(op==3) cout<<tr.order_of_key(to(x,0))+1<<endl;
if(op==4) cout<<bk(*tr.find_by_order(x-1))<<endl;//答案解密
if(op==5) cout<<bk(*(--tr.lower_bound(to(x,0))))<<endl;
if(op==6) cout<<bk(*(tr.upper_bound(to(x,n))))<<endl;
}
return 0;
}
图论
存储图
链式前向星
struct Edge{
int to,w,nxt;
}e[MAXM];
int head[MAXN],num;
void add(int from,int to,int w){
e[++num]=(Edge){to,w,head[from]};
head[from]=num;
}
传递闭包
Floyd
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
G[i][j]=G[i][j]|G[i][k]&G[k][j];
}
}
}
Floyd+bitset
for(int j=1;j<=n;j++){
for(int i=1;i<=n;i++){
if(G[i][j]) G[i]|=G[j];
}
}
最短路
| BFS | dij | dij+堆 | Bellman-Ford | Floyd | SPFA | |
|---|---|---|---|---|---|---|
| 注 | 边权为1 | 边权非负 | 边权非负 | 慢 | 被菊花图卡 | |
| 时间 | \(n+m\) | \(n^2\) | \(m \log m\) | \(nm\) | \(n^3\) | \(m \le SPFA \le nm\) |
| n,m范围 | \(n<5000\) | \(m<1e6,n>1e4\) | \(nm<1e9\) | \(n<400\) | \(m<1e6,n>1e4\) | |
| 其他 | 单源 | 单源 | 单源 | 单源 | 多源 | 单源 |
Bellman-Ford优化
struct Edge{
int from,to,w;
}e[500005];//注意!!!如果是无向图开2倍
int n,m,s,u,v,w;
int d[10005];
int main(){
cin>>n>>m>>s;
memset(d,0x3f,sizeof(d));
for(int i=1;i<=m;i++){
cin>>u>>v>>w;
e[i]=(Edge){u,v,w};
if(u==s) d[v]=w;
}d[s]=0;
//Bellman-Ford
for(int i=1;i<=n-1;i++){
bool check=0;//注意,这里增加了一个布尔变量
for(int j=1;j<=m;j++){
// d[e[j].to]=min(d[e[j].to],e[j].w+d[e[j].from]);
if(d[e[j].to]>e[j].w+d[e[j].from]){
check=1;
d[e[j].to]=e[j].w+d[e[j].from];
}
}
if(check==0) break;
}
for(int i=1;i<=n;i++){
if(d[i]==0x3f3f3f3f) cout<<0x7fffffff<<' ';
else cout<<d[i]<<' ';
}
堆优dijkstra+邻接表
struct node{
int v,w;
friend bool operator< (node x,node y){
return x.w>y.w;
}
};
vector<node> G[100005];
void dij(int s){
for(int i=1;i<=n;i++) ans[i]=INF;
ans[s]=0;
priority_queue<node> q;
q.push((node){s,0});
while(!q.empty()){
int u=q.top().v;q.pop();
if(vis[u]) continue;vis[u]=1;
for(int i=0;i<G[u].size();i++){
int v=G[u][i].v,w=G[u][i].w;
if(ans[v]>ans[u]+w){
ans[v]=ans[u]+w;
q.push((node){v,ans[v]});
}
}
}
}
堆优dijkstra+链式前向星
//链式前向星
struct Edge{
int to,w,next;
}e[200005];
struct Node{
int x,y;
friend bool operator < (Node a,Node b){
return a.y>b.y;
}
};
int head[100005];
int d[100005];
int num,n,m,s,u,v,w;
void addEdge(int from,int to,int w){
e[++num]=(Edge){to,w,head[from]};
head[from]=num;
return;
}
//Dijkstra
priority_queue<Node> q;
void dij(int s){
memset(d,0x3f,sizeof(d));
for(int i=head[s];i;i=e[i].next){
d[e[i].to]=e[i].w;
}
d[s]=0;
f[s]=1;
while(!q.empty()){
int x=q.top().x;q.pop();
if(f[x]==1) continue;
f[x]=1;
for(int i=head[x];i;i=e[i].next){
if(d[e[i].to]>d[x]+e[i].w){
d[e[i].to]=d[x]+e[i].w;
q.push((Node){e[i].to,d[e[i].to]});
}
}
}
}
Johnson
int n,m;
const int N=3005,M=6005;
int head[N],cnt=0;
struct node{
int to,w,nxt;
}e[M<<1];
void addEdge(int u,int v,int w){
e[++cnt]={v,w,head[u]};
head[u]=cnt;
}
int h[N];
bool vis[N];
bool spfa(){
memset(h,0x3f,sizeof(h));h[0]=0;
memset(vis,0,sizeof(vis));
queue<int> q;
q.push(0);
int cnt[N]={0};
vis[0]=1;
while(!q.empty()){
int f=q.front();q.pop();
vis[f]=0;
for(int i=head[f];i;i=e[i].nxt){
int v=e[i].to,w=e[i].w;
if(h[v]>h[f]+w){
h[v]=h[f]+w;
if(!vis[v]){
vis[v]=1;
q.push(v);
cnt[v]++;
if(cnt[v]>n) return 0;
}
}
}
}
return 1;
}
int dis[N];
#define pii pair<int,int>
void dij(int s){
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
priority_queue<pii,vector<pii>,greater<pii> > q;
dis[s]=0;
q.push(mkp(dis[s],s));
while(!q.empty()){
int u=q.top()._2nd;q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to,w=e[i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
q.push(mkp(dis[v],v));
}
}
}
}
signed main(int argc,char *argv[]){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m;
up(i,1,m){
int u,v,w;
cin>>u>>v>>w;
addEdge(u,v,w);
}
up(i,1,n) addEdge(0,i,0);
if(!spfa()){
cout<<-1<<endl;
return 0;
}
up(i,1,n){
for(int j=head[i];j;j=e[j].nxt){
e[j].w=e[j].w+h[i]-h[e[j].to];
}
}
up(i,1,n){
dij(i);
ll ans=0;
up(j,1,n){
if(dis[j]==0x3f3f3f3f) ans+=1000000000ll*j;
else ans+=1ll*j*(dis[j]-h[i]+h[j]);
}
cout<<ans<<endl;
}
return 0;
}
tarjan 全家桶
缩点 SCC
void tarjan(int x){
dfn[x]=low[x]=++d;
in[x]=1;
st.push(x);
for(int i=head[x];i;i=e[i].nxt){
int to=e[i].to;
if(!dfn[to]){
tarjan(to);
low[x]=min(low[x],low[to]);
}else if(in[to]){
low[x]=min(low[x],dfn[to]);
}
}
if(dfn[x]==low[x]){
tot++;
int t=0;
do{
t=st.top();st.pop();
scc[t]=tot;
in[t]=0;
}while(x!=t);
}
}
求割点
void tarjan(int x){
dfn[x]=low[x]=++d;
int sum=0;
for(int i=head[x];i;i=e[i].nxt){
int to=e[i].to;
if(!dfn[to]){
sum++;
tarjan(to);
low[x]=min(low[x],low[to]);
if(cut[x]) continue;
if(x==rt) cut[x]=(sum>1);
else cut[x]=(dfn[x]<=low[to]);
}else low[x]=min(low[x],dfn[to]);
}
}
二分图
匈牙利算法
bool find(int x){
for(int i=0;i<G[x].size();i++){
int to=G[x][i];
if(vis[to]) continue;//连过了
vis[to]=1;
if(line[to]==-1||find(line[to])){//没连过或可以找别的
line[to]=x;//连上
return 1;
}
}
return 0;
}
int hungary(){
memset(line,-1,sizeof(line));
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
if(find(i)) ans++;//能找到
}
return ans;
}
网络最大流
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define int long long
using namespace std;
const ll inf=LONG_LONG_MAX;
int n,m,s,t;
int ans=0;
struct Edge{
int to,w,nxt;
}e[10005];
int num=1,head[205];
void add(int from,int to,int w){
e[++num]=(Edge){to,w,head[from]};
head[from]=num;
}
int dis[205],now[205];
bool bfs(){//构造分层图
for(int i=1;i<=n;i++) dis[i]=inf;
queue<int> q;
q.push(s);
dis[s]=0;
now[s]=head[s];
while(!q.empty()){
int x=q.front();q.pop();
for(int i=head[x];i;i=e[i].nxt){
int to=e[i].to;
if(e[i].w&&dis[to]==inf){
q.push(to);
now[to]=head[to];
dis[to]=dis[x]+1;
if(to==t) return 1;
}
}
}
return 0;
}
int dfs(int x,int sum){//sum是整条增广路对最大流的贡献
if(x==t) return sum;
int ans=0;
for(int i=now[x];i&∑i=e[i].nxt){
now[x]=i;//当前弧优化
int to=e[i].to;
if(e[i].w&&(dis[to]==dis[x]+1)){
int k=dfs(to,min(sum,e[i].w));//当前最小的剩余容量
if(k==0) dis[to]=inf;//剪枝,去掉增广完毕的点
e[i].w-=k;
e[i^1].w+=k;
ans+=k;//经过该点的所有流量和
sum-=k;//经过该点的剩余流量
}
}
return ans;
}
signed main(int argc,char *argv[]){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(NULL);
cin.tie(0),cout.tie(0);
cin>>n>>m>>s>>t;
for(int i=1,u,v,w;i<=m;i++){
cin>>u>>v>>w;
add(u,v,w);
add(v,u,0);
}
while(bfs()) ans+=dfs(s,inf);
cout<<ans<<endl;
return 0;
}
最小生成树
Kruskal 克鲁斯卡尔
sort(Edge+1,Edge+m+1);
for(int i=1;i<=m;i++){
if(find(Edge[i].from)!=find(Edge[i].to)){
cnt++;
ans+=Edge[i].w;
merge(Edge[i].from,Edge[i].to);
}
if(cnt==n-1) break;
}
prim 普雷姆
void prim(){
memset(dis,0x3f,sizeof(dis));
dis[1]=0;
while(1){
int u=0;
for(int i=1;i<=n;i++){
if(!vis[i]&&dis[i]<dis[u]) u=i;
}
if(!u) break;
tot++;vis[u]=1;ans+=dis[u];
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
int w=e[i].w;
if(dis[v]>w) dis[v]=w;
}
}
}
最小斯坦纳树
int n,m,k;
const int N=105,M=505,K=2005;
struct Edge{
int v,w,nxt;
}e[M<<1];
int head[N],cnt=0;
void addEdge(int u,int v,int w){
e[++cnt]=(Edge){v,w,head[u]};
head[u]=cnt;
}
int key[N],dp[N][K];
priority_queue<pi,vector<pi>,greater<pi> > q;
bool vis[N];
void dij(int s){
memset(vis,0,sizeof(vis));
while(!q.empty()){
auto f=q.top();q.pop();
int u=f._2;
if(vis[u]) continue;
vis[u]=1;
for(auto i=head[u];i;i=e[i].nxt){
int to=e[i].v;
if(dp[to][s]>dp[u][s]+e[i].w){
dp[to][s]=dp[u][s]+e[i].w;
q.push(mkp(dp[to][s],to));
}
}
}
}
signed main(int argc,char *argv[]){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m>>k;
up(i,1,m){
int u,v,w;
cin>>u>>v>>w;
addEdge(u,v,w);
addEdge(v,u,w);
}
memset(dp,0x3f,sizeof(dp));
up(i,1,k){
cin>>key[i];
dp[key[i]][1<<(i-1)]=0;
}
up(s,1,(1<<k)-1){
up(i,1,n){
for(int t=s;t;t=(t-1)&s){
dp[i][s]=min(dp[i][s],dp[i][t]+dp[i][s^t]);
}
if(dp[i][s]!=0x3f3f3f3f) q.push(mkp(dp[i][s],i));
}
dij(s);
}
cout<<dp[key[1]][(1<<k)-1]<<endl;
return 0;
}
严格次小生成树
const int N=1e5+5;
const int M=3*1e5+5;
int n,m;
int fa[N];//并查集
bool vis[M];//这个边是否在最小生成树中
struct Edge{
int u,v,w;
friend bool operator< (Edge a,Edge b){
return a.w<b.w;
}
}G[M<<1];
vector<Edge> mst[N];
int e;
int find(int x){
if(fa[x]==x) return x;
else return fa[x]=find(fa[x]);
}
void merge(int x,int y){
int a=find(x),b=find(y);
if(a!=b) fa[a]=b;
}
int sum=0;//最小生成树边权和
void kruskal(){
sort(G+1,G+m+1);
up(i,1,n) fa[i]=i;//初始化并查集
int cnt=0;
up(i,1,m){
int u=G[i].u,v=G[i].v,w=G[i].w;
if(find(u)!=find(v)){
merge(u,v);
vis[i]=1;
cnt++;
sum+=w;
mst[u].push_back((Edge){u,v,w});
mst[v].push_back((Edge){v,u,w});
}
if(cnt==n-1) return;
}
}
int d[N],f[N][30],m1[N][30],m2[N][30];
void dfs(int x,int from,int w){
//if(len>5) return;
//cout<<x<<endl;
d[x]=d[from]+1;
f[x][0]=from;
m1[x][0]=w;
m2[x][0]=-inf;
up(i,1,20){
f[x][i]=f[f[x][i-1]][i-1];
m1[x][i]=max(m1[x][i-1],m1[f[x][i-1]][i-1]);
m2[x][i]=max(m2[x][i-1],m2[f[x][i-1]][i-1]);
if(m1[x][i-1]>m1[f[x][i-1]][i-1]) m2[x][i]=max(m2[x][i],m1[f[x][i-1]][i-1]);
else if(m1[x][i-1]<m1[f[x][i-1]][i-1]) m2[x][i]=max(m2[x][i],m1[x][i-1]);
}
for(auto to:mst[x]){
if(to.v==from) continue;
dfs(to.v,x,to.w);
}
}
int LCA(int x,int y){
if(d[x]<d[y]) swap(x,y);//d[x]>d[y]
dn(i,20,0){
if(d[f[x][i]]>=d[y]) x=f[x][i];
}
if(x==y) return x;
dn(i,20,0){
if(f[x][i]!=f[y][i]){
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
int work(int x,int y,int maxn){
int ans=-inf;
dn(i,20,0){
if(d[f[x][i]]>=d[y]){
if(maxn!=m1[x][i]) ans=max(ans,m1[x][i]);
else ans=max(ans,m2[x][i]);
x=f[x][i];
}
}
return ans;
}
signed main(int argc,char *argv[]){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m;
up(i,1,m){
int u,v,w;
cin>>u>>v>>w;
G[i]={u,v,w};
}
kruskal();
dfs(1,0,0);
int ans=inf;
up(i,1,m){
if(vis[i]) continue;
int u=G[i].u,v=G[i].v,w=G[i].w;
int lca=LCA(u,v);
int mu=work(u,lca,w),mv=work(v,lca,w);
ans=min(ans,sum-max(mu,mv)+w);
}
cout<<ans<<endl;
return 0;
}
dp
01背包
for(int i=1;i<=m;i++){
for(int j=t;j>=w[i];j--){
dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
}
}
01背包算方案数
dp[0]=1;//dp[j]为凑到重量为j的方案数
for(int i=1;i<=n;i++){
for(int j=m,j>=a[i];j--){
dp[j]+=dp[j-a[i]];
}
}
完全背包
for(int i=1;i<=m;i++){
for(int j=w[i];j<=t;j++){
dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
}
}
多重背包+二进制优化
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a>>b>>s;
for(int j=1;j<=s;j*=2){
num++;
//放入体积、价值
w[num]=a*j;
c[num]=b*j;
s-=j;//一直往下扣2^n
}
if(s!=0){
//没放完,把最后的常数放进去
num++;
w[num]=a*s;
c[num]=b*s;
}
}
//01
for(int i=1;i<=num;i++){
for(int j=m;j>=w[i];j--){
dp[j]=max(dp[j],dp[j-w[i]]+c[i]);//经典01背包模板
}
}
数位 dp 模板
const int N=105;
int a[N];
ll f[N][N];
//如果有前导零还要加一个lead参数
ll dfs(int pos,int sta,bool lim){
if(!pos) return 0;//到了最后一位,根据题意决定返回值
if(!lim&&f[pos][sta]==-1) return f[pos][sta];
ll ans=0,top=lim?a[pos]:9;//如果受限只能搜到a[pos]
for(int i=0;i<=top;i++){
int newsta;
if(1) newsta=sta+1;//满足条件,更新状态
//状态转移
ans+=dfs(pos-1,newsta,lim&&i==top);
}
//不受限才记录
if(!lim) f[pos][sta]=ans;
return ans;
}
ll solve(ll x){
memset(f,-1,sizeof(f));//不要忘记初始化
int cnt=0;
while(x) a[++cnt]=x%10,x/=10;
//lim始终为1
//sta初始值根据题来定
return dfs(pos,0,1);
}
字符串算法
马拉车 manacher
void work(){
n=s.size();
string str="$";
up(i,0,n-1){
str+="#";
str+=s[i];
}
str+="#&";
s=str;
n=s.size();
}
void HorsePullCar(){
up(i,1,n-1){
if(i<r) p[i]=min(p[(c<<1)-i],r-i);
else p[i]=1;
while(s[i+p[i]]==s[i-p[i]]) p[i]++;
if(p[i]+i>r){
r=p[i]+i;
c=i;
}
}
}

浙公网安备 33010602011771号