NOIP复赛模板及技巧积累(不定期更新)

一.对拍

新建 1.bat,然后编辑

:loop
date.exe
pro.exe
check.exe
fc pro.out check.out
if %errorlevel%==0 goto loop

二.考试须知

1.内存(小心开炸,爆零)

若使用了结构体
可在主函数中:

printf("%lf\n",sizeof(P30)/1024.0/1024);

2.两数相乘(炸int)
3.取模(题目看仔细)
4.long long(注意数据范围)
5.文件名(复制)
6.读入输出(查看读入输出文件名)
7.输出调试(一定得关掉)

三.造数据

1.造树

    srand(time(NULL));
    int n;
    cin>>n;
    for(int i=0;i<n;i++)A[i]=i+1;
    for(int i=1;i<=1e6;i++){
        swap(A[rand()%n],A[rand()%n]);
    }
    for(int i=1;i<n;i++)printf("%d %d\n",A[rand()%i],A[i]);

注意:rand()大约只有3万多

四.日常加速

1.读入挂

void Rd(int &res){
    res=0;char c;
    while(c=getchar(),c<48);
    do res=(res<<3)+(res<<1)+(c&15);
    while(c=getchar(),c>=48);
}

建议不要读负数

2.正向表

适用于图论中代替vector

int nxt[M<<1],head[M],To[M],V[M],ttaE;
void addedge(int a,int b,int c){
    nxt[++ttaE]=a;head[a]=ttaE;
    To[tta]=b;V[tta]=c;
}

3.手打堆

五.图论

1.迪杰斯特拉

如果加上手打堆会超快

struct node{
    int v,id;
    bool operator<(const node &s)const{
        return v>s.v;
    }
};
priority_queue<node>q;
void dij(int x){
    memset(dis,0,sizeof(dis));
    dis[x]=0;
    q.push((node){0,x});
    while(!q.empty()){
        node now=q.top();q.pop();
        if(dis[now.id]<now.v)continue;
        LFOR(i,x){
            int y=To[i];
            int v=V[i];
            if(dis[y]==-1||dis[y]>dis[x]+v){
                dis[y]=dis[x]+v;
                q.push((node){dis[y],y});
            }
        }
    }
}

2.SPFA

实现较为轻松,一般情况跑得较快,但复杂度玄学,可能被卡成n*m

void spfa(int x){
    memset(dis,-1,sizeof(dis));
    memset(mark,0,sizeof mark);
    mark[x]=1;
    queue<int>q;
    q.push(x);
    while(!q.empty()){
        int now=q.front();q.pop();
        mark[now]=0;
        LFOR(i,x){
            int nxt=To[i];
            if(dis[nxt]>dis[now]+V[i]||dis[nxt]==-1){
                dis[nxt]=dis[now]+V[i];
                if(!mark[nxt]){
                    q.push(nxt);
                    mark[nxt]=1;
                }
            }
        }
    }
}

3.Bell_man

可判负环

void relax(int u,int v,int w){
    if(dis[u]>dis[v]+w)dis[u]=dos[v]+w;
}
void bellman(){
    for(int i=1;i<n;i++){
        for(int j=1;j<=m;j++){
            relax(edge[j].x,edge[j].y,edge[j].v);
        }
    }
    //判负环
    bool flag=0;
    for(int i=1;i<=m;i++){
        if(dis[edge[i].x]>dis[edge[i].y]+edge[i].v){flag=1;break;}
    }
    return flag;
}

4.floyd

水分利器,再次强调三层for的顺序

for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            chk_mi(dis[i][j],dis[i][k]+dis[k][j]);

5.最小生成树

这里只介绍kruskal算法 因为它快而且简单啊

struct EDGE{
    int v,x,y;
    bool operator <(const EDGE &_){
        return v<_.v;
    }
}edge[M];
int fa[M];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int kruskal{
    int ans=0;
    sort(edge+1,edge+m+1);
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++){
        int a=find(edge[i].x),b=find(edge[i].y);
        if(a!=b){
            ans+=edge[i].v;
            fa[a]=b;
        }
    }
    return ans;
} 

6.LCA(倍增)

实现容易,比树链剖分慢一些

void dfs(int x,int f){
    fa[0][x]=f;dep[x]=dep[f]+1;
    LFOR(i,x){
        int y=To[i];
        if(y==f)continue;
        dfs(y,x);
    }
}
void init(){
    for(int i=1;i<S;i++)
        for(int j=1;j<=n;j++)
            fa[i][x]=fa[i-1][fa[i-1][x]];
}
void Up(int &x,int len){
    for(int i=0;i<S;i++)if(len&(1<<i))x=fa[i][x];
}
int LCA(int x,int y){
    if(dep[x]>dep[y])swap(x,y);
    Up(y,dep[y]-dep[x]);
    if(x==y)return x;
    for(int i=S-1;i>=0;i--){
        if(fa[i][x]!=fa[i][y]){
            x=fa[i][x];
            y=fa[i][y];
        }
    }
    return fa[0][x];
}

7.LCA(树链剖分)

听说均摊复杂度比tarjan【O(1)】还快 orz;

#include<bits/stdc++.h>
using namespace std;
int sz[M],son[M],fa[M],Top[M],dep[M];
void ldfs(int x,int f){
    sz[x]=1,son[x]=-1;
    fa[x]=f,dep[x]=dep[f]+1;
    LFOR(i,x){
        int y=To[i];
        if(y==f)continue;
        ldfs(y,x); 
        sz[x]+=sz[y];
        if(!~son[x]||sz[son[x]]<sz[y])son[x]=y;
    }
}
void rdfs(int x,int tp){
    Top[x]=tp;
    if(!~son[x])return;
    rdfs(son[x],tp);
    LFOR(i,x){
        int y=To[i];
        if(y==son[x]||y==fa[x])continue;
        rdfs(y,y);
    }
}
int LCA(int x,int y){
    while(Top[x]!=Top[y]){
        if(dep[Top[x]]>dep[Top[y]])x=fa[Top[x]];
        else y=fa[Top[y]];
    }
    return dep[x]<dep[y]?x:y;
}

六.数论

1.gcd

图轮只会打模板
贪心只能过样例
dp打表找规律
数论只会gcd


void gcd(int x,int y){return !x?y:gcd(y,x%y);}

2.ex_gcd

主要套了gcd的壳
这样可以算出一组解,然后满足x=x0+kb y=y0-ka;
当满足b==0是x=0,y=1;然后 y=y-x*(a/b);

void exgcd(int a,int b,int &c,int &x,int &y){
    if(!b){c=a,x=1,y=0;return;}
    else exgcd(b,a%b,c,y,x);y-=x*(a/b);
} 

3.快速幂

ll fast(ll x,ll n,ll P){
    ll res=1;
    while(n){
        if(n&1)res=res*x%P;
        n=n>>1;
        x=x*x%P;
    }
    return res;
}

4.组合数

1.递推

for(int i=1;i<=n;i++){
    C[i][0]=C[i][i]=1;
    for(int j=1;j<i;j++)C[i][j]=C[i-1][j]+C[i-1][j-1];
}

2.逆元
O(nlogn)求以n为底的组合数

    C[0]=1;
    for(int i=1;i<=n;i++)C[i]=C[i-1]*(n-i+1)%P*fast(i,P-2)%P;

3.线性求逆元
复杂度为O(n)

B[1]=1; 
FOR(i,2,n)B[i]=1LL*(Mod-Mod/i)*B[Mod%i]%Mod;

5.埃氏筛法

void init(){
    for(int i=2;i<=n;i++){
        if(mark[i])continue;
        for(int j=i+i;j<=n;j+=i)mark[j]=1;
    }
}

七.数据结构

1.线段树

(以区间最值为例子)
1.单点更新,区间查询

struct Segment_Tree{
    #define Lson l,mid,p<<1
    #define Rson mid+1,r,p<<1|1
    struct node{int l,r,mx;}tree[M<<2];//a为延时标记 
    void up(int p){
        tree[p].mx=max(tree[p<<1].mx,tree[p<<1|1].mx);
    }
    void build(int l,int r,int p){
        tree[p].l=l,tree[p].r=r;
        if(l==r){
            tree[p].mx=A[l];
            return;
        }
        int mid=(l+r)>>1;
        build(Lson);build(Rson); 
        up(p);
    }
    void update(int pos,int x,int p){
        if(tree[p].l==l&&tree[p].r==r){
            tree[p].mx=x;
            return;
        }
        int mid=(tree[p].l+tree[p].r)>>1;
        if(mid>=pos)update(pos,x,p<<1);
        else update(pos,x,p<<1|1);
        up(p);
    }
    int query(int l,int r,int p){
        if(tree[p].l==l&&tree[p].r==r){
            return tree[p].mx;
        }
        int mid=(tree[p].l+tree[p].r)>>1;
        if(mid>=r)return query(l,r,p<<1);
        else if(mid<l)return query(l,r,p<<1|1);
        else return max(query(Lson),query(Rson));
    }
}Tree;

2.区间更新,单点查询

struct Segment_Tree{
    #define Lson l,mid,p<<1
    #define Rson mid+1,r,p<<1|1
    struct node{int l,r,mx;}tree[M<<2];//a为延时标记 
    void up(int p){
        tree[p].mx=max(tree[p<<1].mx,tree[p<<1|1].mx);
    }
    void build(int l,int r,int p){
        tree[p].l=l,tree[p].r=r;
        if(l==r){
            tree[p].mx=A[l];
            return;
        }
        int mid=(l+r)>>1;
        build(Lson);build(Rson); 
        up(p);
    }
    void update(int l,int r,int x,int p){
        if(tree[p].l==l&&tree[p].r==r){
            tree[p].mx=x;
            return;
        }
        int mid=(tree[p].l+tree[p].r)>>1;
        if(mid>=r)update(l,r,x,p<<1);
        else if(mid<l)update(l,r,x,p<<1|1);
        else update(l,mid,x,p<<1),update(mid+1,r,x,p<<1|1);
        up(p);
    }
    int query(int pos,int p){
        if(tree[p].l==tree[p].r){
            return tree[p].mx;
        }
        int mid=(tree[p].l+tree[p].r)>>1;
        if(mid>=pos)return max(tree[p].mx,query(pos,p<<1));
        else return max(tree[p].mx,query(pos,p<<1|1));
    }
}Tree;

3.区间更新,区间查询

struct Segment_Tree{
    #define Lson l,mid,p<<1
    #define Rson mid+1,r,p<<1|1
    struct node{int l,r,mx,a;}tree[M<<2];//a为延时标记 
    void up(int p){
        tree[p].mx=max(tree[p<<1].mx,tree[p<<1|1].mx);
    }
    void down(int p){
        if(!tree[p].a)return;
        tree[p<<1].a=tree[p].a,tree[p<<1|1].a=tree[p].a;
        tree[p<<1].mx=tree[p].mx,tree[p<<1|1].mx=mx;
        tree[p].a=0;
    }
    void build(int l,int r,int p){
        tree[p].l=l,tree[p].r=r,tree[p].a=0;
        if(l==r){
            tree[p].mx=A[l];
            return;
        }
        int mid=(l+r)>>1;
        build(Lson);build(Rson); 
        up(p);
    }
    void update(int l,int r,int x,int p){
        if(tree[p].l==l&&tree[p].r==r){
            tree[p].mx=x;
            tree[p].a=1;
            return;
        }
        down(p);
        int mid=(tree[p].l+tree[p].r)>>1;
        if(mid>=r)update(l,r,x,p<<1);
        else if(mid<l)update(l,r,x,p<<1|1);
        else update(l,mid,x,p<<1),update(mid+1,r,p<<1|1);
        up(p);
    }
    int query(int l,int r,int p){
        if(tree[p].l==l&&tree[p].r==r){
            return tree[p].mx;
        }
        down(p);
        int mid=(tree[p].l+tree[p].r)>>1;
        if(mid>=r)return query(l,r,p<<1);
        else if(mid<l)return query(l,r,p<<1|1);
        else return max(query(Lson),query(Rson));
    }
}Tree;

2.BIT

主题思想是前缀和
空间复杂度和时间复杂度还有代码长度都是线段树的四分之一

struct BIT{
    #define lowbit(x) x&-x
    int Sum[M]
    void update(int x,int a){
        while(x<=n){
            Sum[x]+=a;
            x+=lowbit(x);
        }
    }
    int query(int x){
        int res=0;
        while(x){
            res+=Sum[x];
            x-=lowbit(x); 
        }
        return res;
    }
}Bit;

3.并查集

void init(int n){for(int i=1;i<=n;i++)fa[i]=i;}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void unite(int x,int y){fa[find(x)]=find(y);}
bool same(int x,int y){return find(x)==find(y);}

4.高精度

已经过性能测试,可能还存在什么小bug
大部分的功 能都有

#include<bits/stdc++.h>
using namespace std;
struct Bignum{
    int A[1005],len;
    static const int P=10000;
    Bignum(){memset(A,0,sizeof A);len=1;}
    void Rd(){
        char C[1005];
        scanf("%s",C+1);
        int n=strlen(C+1);
        len=0;
        for(int i=n;i>=1;i-=4){
            len++;
            A[len]=0;
            for(int j=max(1,i-3);j<=i;j++){
                A[len]=(A[len]<<3)+(A[len]<<1)+(C[j]&15);
            }
        }
        while(len>1&&!A[len])len--;
    } 
    Bignum operator +(const Bignum &S)const{
        Bignum tmp;
        tmp.len=max(S.len,len);
        for(int i=1;i<=tmp.len;i++){
            tmp.A[i]+=A[i]+S.A[i];
            if(tmp.A[i]>=P){
                tmp.A[i]-=P;
                tmp.A[i+1]++;
            }
        }
        if(tmp.A[tmp.len+1])tmp.len++;
        return tmp;
    }
    Bignum operator *(const Bignum &S)const{
        Bignum tmp;
        tmp.len=S.len+len-1;
        for(int i=1;i<=len;i++){
            for(int j=1;j<=S.len;j++){
                tmp.A[i+j-1]+=A[i]*S.A[j];
                tmp.A[i+j]+=tmp.A[i+j-1]/P;
                tmp.A[i+j-1]=tmp.A[i+j-1]%P;
            }
        }
        if(tmp.A[tmp.len+1])tmp.len++;
        while(!tmp.A[tmp.len]&&tmp.len>1)tmp.len--; 
        return tmp;
    }
    Bignum operator -(const Bignum &S)const{
        Bignum tmp;
        tmp.len=max(S.len,len);
        for(int i=tmp.len;i>=1;i--){
            tmp.A[i]+=A[i]-S.A[i];
            if(tmp.A[i]<0){
                tmp.A[i]+=P;
                tmp.A[i+1]--;
            }
        }
        while(!tmp.A[tmp.len])tmp.len--;
        return tmp;
    }
    bool operator <(const Bignum &S)const{
        if(S.len!=len)return len<S.len;
        for(int i=len;i>=1;i--){
            if(A[i]!=S.A[i])return A[i]<S.A[i];
        }
        return 0;
    }
    bool operator ==(const Bignum &S)const{
        if(len!=S.len)return 0;
        for(int i=1;i<=len;i++){
            if(A[i]!=S.A[i])return 0;
        }
        return 1;
    }
    bool operator <=(const Bignum &S)const{
        return *this<S||*this==S;
    }
    Bignum operator /(const int &p)const{
        Bignum tmp=*this;
        for(int i=len;i>=1;i--){
            if(i>1)tmp.A[i-1]+=tmp.A[i]%p*P;
            tmp.A[i]=tmp.A[i]/p;
        }
        while(tmp.len>1&&!tmp.A[tmp.len])tmp.len--;
        return tmp;
    }
    Bignum operator +(const int &p)const{
        Bignum tmp;
        tmp=*this;
        tmp.A[1]+=p;
        int now=1;
        while(tmp.A[now]>=P){
            tmp.A[now+1]++;
            tmp.A[now]-=P;
            now++;
        }
        if(tmp.A[tmp.len+1])tmp.len++;
        return tmp;
    }
    Bignum operator -(const int &p)const{
        Bignum tmp;
        tmp=*this;
        tmp.A[1]-=p;
        int now=1;
        while(tmp.A[now]<0){
            tmp.A[now+1]--;
            tmp.A[now]+=P;
            now++;
        }
        if(!tmp.A[tmp.len]&&tmp.len>1)tmp.len--;
        return tmp;
    }
    Bignum operator /(const Bignum &S)const{
        Bignum l,r,res;
        if(*this<S)return res;
        r=*this;
        while(l<=r){
            Bignum mid=(l+r)/2;
            if((mid*S)<=*this){
                res=mid;
                l=mid+1;
            }
            else r=mid-1;
        }
        return res;
    }
    void print(){
        printf("%d",A[len]);
        for(int i=len-1;i>0;i--)printf("%04d",A[i]);puts("");
    }
}a,b,c;
int main(){
    a.Rd(),b.Rd();
    c=a/b;
    c.print();
    return 0;
} 

八.排序

1.归并排序

2.快速排序

3.堆排序

9.错误小结

1.与系统变量冲突

(25126)全局变量y1,y0
(25081)全局函数名hash
(24221)全局函数名begin
(24198)全局数组名rank
(23836)全局数组名next
(21994)全局数组名log2
(19969)全局数组名less
(19960)全局数组名ws
(18453)全局数组名prev
(15807)全局数组名pow
(13017)全局数组名time
(11360)全局数组名end
(9924)全局数组名index
(12213)全局数组名cos

十.小工具

Mul

两数相乘可能会炸long long,但同时要取模,可以用Mul函数

LL Mul(LL x,LL y,LL p){
    x=(x%p+x)%p;
    y=(x%p+y)%p;
    LL res=0;
    while(y){
        if(y&1)res=(res+x)%p;
        y>>=1;
        x=(x+x)%p;
    }
    return res;
} 

C

组合数
注意i < j的情况

LL C(LL i,LL j,LL p){
    if(i<j)return 0;
    return A[i]*fast(A[j],p-2,p)%p*fast(A[i-j],p-2,p)%p;
}
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值