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

来源:互联网 发布:软件基础架构平台 编辑:程序博客网 时间:2024/06/03 22:50

一.对拍

新建 1.bat,然后编辑

:loopdate.exepro.execheck.exefc pro.out check.outif %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

原创粉丝点击