• NOIP的基本模板合集(2)


    目录:

    1.堆

    2.扩展中国剩余定理

    3.线段树

    4.并查集

    5.最小生成树

    6.最短路

    7.离散化

    8.tarjan缩点

    9.KMP算法

    10.高斯消元法

    一.堆(stl版)

    1.大根堆

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    priority_queue < int , vector < int > > q;
    int n;
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            int x,y;
            scanf("%d",&x);
            if(x==1)//将y插入到堆中
            {
                scanf("%d",&y);
                q.push(y);
            }
            if(x==2)//删除该大根堆内的最大数
            {
                q.pop();
            }
            if(x==3)//输出该大根堆内的最大数
            {
                printf("%d
    ",q.top());
            }
        }
    }

    2.小根堆

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    priority_queue < int , vector < int > , greater < int > > q;
    int n;
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            int x,y;
            scanf("%d",&x);
            if(x==1)//将y插入到堆中
            {
                scanf("%d",&y);
                q.push(y);
            }
            if(x==2)//删除该小根堆内的最小数
            {
                q.pop();
            }
            if(x==3)//输出该小根堆内的最小数
            {
                printf("%d
    ",q.top());
            }
        }
    }

    二.扩展中国剩余定理

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<vector>
    using namespace std;
    long long n,ai[100001],bi[100001];
    long long mul(long long x,long long y,long long p)
    {
        long long ans=0;
        while(y)
        {
            if(y&1)
                ans=(ans+x)%p;
            x=(x+x)%p;
            y>>=1;
        }
        return ans;
    }
    long long exgcd(long long a,long long b,long long &x,long long &y)
    {
        if(b==0)
        {
            x=1;
            y=0;
            return a;
        }
        long long cnt=exgcd(b,a%b,x,y);
        long long idx=x;
        x=y;
        y=idx-a/b*y;
        return cnt;
    }
    long long excrt()
    {
        long long x=0,y=0;
        long long M=bi[1],ans=ai[1];
        for(long long i=2;i<=n;i++)
        {
            long long a=M,b=bi[i],c=((ai[i]-ans)%b+b)%b;
            long long gcd=exgcd(a,b,x,y),idx=b/gcd;
            if(c%gcd!=0)
                return -1;
            x=mul(x,c/gcd,idx);
            ans+=x*M;
            M*=idx;
            ans=(ans%M+M)%M;
        }
        return (ans%M+M)%M;
    }
    int main()
    {
        scanf("%lld",&n);
        for(long long i=1;i<=n;i++)
            scanf("%lld%lld",&ai[i],&bi[i]);
        printf("%lld
    ",excrt());
    }

    三.线段树

    1.建树

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    using namespace std;
    int n,a[100001],sum[400001];
    void pushup(int k)
    {
        sum[k]=sum[k<<1]+sum[k<<1|1];
    }
    void build(int l,int r,int k)
    {
        if(l==r)
        {
            sum[k]=a[l];
            return;
        }
        int mid=(l+r)>>1;
        build(l,mid,k<<1);
        build(mid+1,r,k<<1|1);
        pushup(k);
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        build(1,n,1);
    }

    2.单点修改(单点加同理)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    using namespace std;
    int n,a[100001],sum[400001],m;
    void pushup(int k)
    {
        sum[k]=sum[k<<1]+sum[k<<1|1];
    }
    void update(int l,int r,int p,int v,int k)
    {
        if(l==r)
        {
            sum[k]=v;
            return;
        }
        int mid=(l+r)>>1;
        if(mid>=p)
            update(l,mid,p,v,k<<1);
        if(mid<p)
            update(mid+1,r,p,v,k<<1|1);
        pushup(k);
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        build(1,n,1);//先建树
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            int x,v;
            scanf("%d%d",&x,&v);
            update(1,n,x,v,1);
        }
    }

    3.区间加

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    using namespace std;
    int n,a[100001],sum[400001],m,tag[400001];
    void pushup(int k)
    {
        sum[k]=sum[k<<1]+sum[k<<1|1];
    }
    void lazy(int l,int r,int v,int k)
    {
        tag[k]+=v;
        sum[k]+=(r-l+1)*v;
    }
    void pushdown(int l,int r,int k)
    {
        int mid=(l+r)>>1;
        lazy(l,mid,tag[k],k<<1);
        lazy(mid+1,r,tag[k],k<<1|1);
        tag[k]=0;
    }
    void update(int l,int r,int x,int y,int v,int k)
    {
        if(x<=l&&r<=y)
        {
            sum[k]+=(r-l+1)*v;
            tag[k]+=v;
            return;
        }
        int mid=(l+r)>>1;
        pushdown(l,r,k);
        if(mid>=x)
            update(l,mid,x,y,v,k<<1);
        if(mid<y)
            update(mid+1,r,x,y,k<<1|1);
        pushup(k);
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        build(1,n,1);//先建树
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            int x,y,v;
            scanf("%d%d%d",&x,&y,&v);
            update(1,n,x,y,v,1);
        }
    }

    4.区间修改

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    using namespace std;
    int n,a[100001],sum[400001],m,tag[400001];
    void pushup(int k)
    {
        sum[k]=sum[k<<1]+sum[k<<1|1];
    }
    void lazy(int l,int r,int v,int k)
    {
        tag[k]=v;
        sum[k]=(r-l+1)*v;
    }
    void pushdown(int l,int r,int k)
    {
        int mid=(l+r)>>1;
        lazy(l,mid,tag[k],k<<1);
        lazy(mid+1,r,tag[k],k<<1|1);
        tag[k]=0;
    }
    void update(int l,int r,int x,int y,int v,int k)
    {
        if(x<=l&&r<=y)
        {
            sum[k]=(r-l+1)*v;
            tag[k]=v;
            return;
        }
        int mid=(l+r)>>1;
        pushdown(l,r,k);
        if(mid>=x)
            update(l,mid,x,y,v,k<<1);
        if(mid<y)
            update(mid+1,r,x,y,k<<1|1);
        pushup(k);
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        build(1,n,1);//先建树
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            int x,y,v;
            scanf("%d%d%d",&x,&y,&v);
            update(1,n,x,y,v,1);
        }
    }

    5.单点查询

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    using namespace std;
    int n,a[100001],sum[400001],m,tag[400001];
    void lazy(int l,int r,int v,int k)
    {
        tag[k]=v;
        sum[k]=(r-l+1)*v;
    }
    void pushdown(int l,int r,int k)
    {
        int mid=(l+r)>>1;
        lazy(l,mid,tag[k],k<<1);
        lazy(mid+1,r,tag[k],k<<1|1);
        tag[k]=0;
    }
    int query(int l,int r,int p,int k)
    {
        if(l==r)
            return sum[k];
        int mid=(l+r)>>1,ans=0;
        pushdown(l,r,k);
        if(mid>=p)
            ans+=query(l,mid,p,k<<1);
        if(mid<p)
            ans+=query(mid+1,r,p,k<<1|1);
        return ans;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        build(1,n,1);//先建树
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            int x;
            scanf("%d",&x);
            int ans=query(1,n,x,1);
            printf("%d
    ",ans);
        }
    }

    6.区间查询

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    using namespace std;
    int n,a[100001],sum[400001],m,tag[400001];
    void lazy(int l,int r,int v,int k)
    {
        tag[k]=v;
        sum[k]=(r-l+1)*v;
    }
    void pushdown(int l,int r,int k)
    {
        int mid=(l+r)>>1;
        lazy(l,mid,tag[k],k<<1);
        lazy(mid+1,r,tag[k],k<<1|1);
        tag[k]=0;
    }
    int query(int l,int r,int x,int y,int k)
    {
        if(x<=l&&r<=y)
            return sum[k];
        int mid=(l+r)>>1,ans=0;
        pushdown(l,r,k);
        if(mid>=x)
            ans+=query(l,mid,x,y,k<<1);
        if(mid<y)
            ans+=query(mid+1,r,x,y,k<<1|1);
        return ans;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        build(1,n,1);//先建树
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            int ans=query(1,n,x,y,1);
            printf("%d
    ",ans);
        }
    }

     四.并查集

    1.路径压缩

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    int n,m,f[10001];
    int find(int p)
    {
        if(p!=f[p])
            f[p]=find(f[p]);
        return f[p];
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            f[i]=i;
        for(int i=1;i<=n;i++)
        {
            int x=find(i);
            printf("%d
    ",x);
        }
    }    

    2.普通合并

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    int n,m,f[10001];
    int find(int p)
    {
        if(p!=f[p])
            f[p]=find(f[p]);
        return f[p];
    }
    void merge(int x,int y)
    {
        int fx=find(x),fy=find(y);
        if(fx!=fy)
            f[fx]=fy;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            f[i]=i;
        for(int i=1;i<=n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            merge(x,y);
        }
    }    

    3.启发式合并

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    int n,m,f[10001],s[10001];
    int find(int p)
    {
        if(p!=f[p])
            f[p]=find(f[p]);
        return f[p];
    }
    void merge(int x,int y)
    {
        int fx=find(x),fy=find(y);
        if(s[fx]<s[fy])
            s[fy]+=s[fx],f[fx]=fy;
        else
            s[fx]+=s[fy],f[fy]=fx;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            f[i]=i;
            s[i]=1;
        }
        for(int i=1;i<=n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            merge(x,y);
        }
    }    

     五.最小生成树

    1.Prim算法

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    int n,l[101][101],minn[101];
    bool used[101];
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;i++)
                scanf("%d",&l[i][j]);
        memset(minn,999999999,sizeof(minn));
        minn[1]=0;
        memset(u,1,sizeof(u));
        for(int i=1;i<=n;i++)
        {
            int k=0;
            for(int j=1;j<=n;j++)
                if(u[j]&&minn[j]<minn[k])
                    k=j;
            u[k]=0;
            for(int j=1;j<=n;j++)
                if(u[j]&&l[k][j]<minn[j])
                    minn[j]=g[k][j];
        }
        int ans=0;
        for(int i=1;i<=n;i++)
            ans+=minn[i];
        prntf("%d
    ",ans);
    }

    2.Kruskal算法

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    int n,f[101],m,tot,k,idx;
    struct Edge
    {
        int x,y,v;
    }a[9001];
    bool cmp(const Edge &a,const Edge &b)
    {
        return a.v<b.v;
    }
    int find(int p)
    {
        if(f[p]!=p)
            f[p]=find(f[p]);
        return f[p];
    }
    void merge(int x,int y)
    {
        int fx=find(x);
        int fy=find(y);
        if(fx!=fy)
            f[fx]=fy;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                int value;
                scanf("%d",&value);
                a[++idx].x=i;
                a[idx].y=j;
                a[idx].v=value;
            }
        for(int i=1;i<=n;i++)
            f[i]=i;
        sort(a+1,a+idx+1,cmp);
        for(int i=1;i<=m;i++)
        {
            if(find(a[i].x)!=find(a[i.y]))
            {
                merge(a[i].x,a[i].y);
                tot+=a[i].v;
                k++;
            }
            if(k==n-1)
                break;
        }
        printf("%d
    ",tot);
    }

    六.最短路

    1.Floyed算法

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    int n,f[101][101],s,t;
    int main()
    {
        scanf("%d",&n);
        memset(f,0x7f,sizeof(f));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&f[i][j]);
        scanf("%d%d",&s,&t);
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if((i!=j)&&(j!=k)&&(j!=k)&&f[i][k]+f[k][j]<f[i][j])
                        f[i][j]=f[i][k]+f[k][j];
        printf("%d",f[s][t]);
    }

    2.Dijkstra算法

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    int f[101][101],n,s,t,minn[101];
    bool vis[101];
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&f[i][j]);
        scanf("%d%d",&s,&t);
        for(int i=1;i<=n;i++)
            minn[i]=f[s][i];
        minn[s]=0;
        vis[s]=1;
        for(int i=1;i<n;i++)
        {
            int k=0,idx=999999999;
            for(int j=1;j<=n;j++)
                if(vis[j]==0&&minn[j]<idx)
                {
                    k=j;
                    idx=minn[j];
                }
            if(k==0)
                break;
            vis[k]=1;
            for(int j=1;j<=n;j++)
                if(minn[k]+f[k][j]<minn[j])
                    minn[j]=minn[k]+f[k][j];
        }
        printf("%d
    ",minn[t]);
    }

    3.Dijkstra堆优化

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    #define    inf 0x3f3f3f3f
    int t,c,ts,te,to[12401],head[12401],nxt[12401],idx,len[12401],minn[3001];
    bool vis[3001];
    priority_queue < pair < int , int > , vector < pair < int , int > > , greater < pair < int , int > > > q;
    void addedge(int a,int b,int c)
    {
        to[++idx]=b;
        len[idx]=c;
        nxt[idx]=head[a];
        head[a]=idx;
    }
    int main()
    {
        scanf("%d%d%d%d",&t,&c,&ts,&te);
        for(int i=1;i<=c;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            addedge(a,b,c);
            addedge(b,a,c);
        }
        memset(minn,inf,sizeof(minn));
        minn[ts]=0;
        q.push(make_pair(0,ts));
        while(!q.empty())
        {
            int p=q.top().second; 
            q.pop();
            if(vis[p])
                continue;
            vis[p]=1;
            for(int i=head[p];i;i=nxt[i])
            {
                if(minn[to[i]]>minn[p]+len[i])
                {
                    minn[to[i]]=minn[p]+len[i];
                    q.push(make_pair(minn[to[i]],to[i]));
                }
            }
        }
        printf("%d",minn[te]);
        return 0;
    }

    4.Spfa算法及判负环(以洛谷模板为例)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<cmath>
    using namespace std;
    int n,m,t,head[100001],idx,dis[100001],cnt[100001],to[100001],nxt[100001],len[100001];
    bool vis[100001];
    void addedge(int x,int y,int z)
    {
        to[++idx]=y;
        nxt[idx]=head[x];
        len[idx]=z;
        head[x]=idx;
    }
    bool spfa(int s)
    {
        memset(vis,0,sizeof(vis));
        memset(dis,0x3f3f3f3f,sizeof(dis));
        memset(cnt,0,sizeof(cnt));
        queue < int > q;
        q.push(s);
        vis[s]=1;
        dis[s]=0;
        while(!q.empty())
        {
            int p=q.front();
            q.pop();
            vis[p]=0;
            for(int i=head[p];i;i=nxt[i])
            {
                if(dis[to[i]]>dis[p]+len[i])
                {
                    dis[to[i]]=dis[p]+len[i];
                    if(!vis[to[i]])
                    {
                        q.push(to[i]);
                        vis[to[i]]=1;
                        cnt[to[i]]++;
                        if(cnt[to[i]]>=n)//判负环部分,若一个点入队大于n次,则它一定在一个环内
                            return 1;
                    }
                }
            }
        }
        return 0;
    }
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&m);
            idx=0;
            memset(head,0,sizeof(head));
            for(int i=1,u,v,w;i<=m;i++)
            {
                scanf("%d%d%d",&u,&v,&w);
                if(w<0)
                    addedge(u,v,w);
                else
                {
                    addedge(u,v,w);
                    addedge(v,u,w);
                }     
            }
            if(spfa(1)==1)
                printf("YE5
    ");
            else
                printf("N0
    ");
        }
    }

    七.离散化

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #include<vector>
    using namespace std;
    int a[10001],b[10001],n,idx;
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            b[++idx]=a[i];
        }
        sort(b+1,b+idx+1);
        idx=unique(b+1,b+n+1)-b-1;
        for(int i=1;i<=n;i++)
            a[i]=lower_bound(b+1,b+idx+1,a[i])-b;
    }

    八.tarjan缩点

    int z[100001],dep[100001],low[100001],top,ans,cnt,neww[100001],f[100001];
    bool inz[100001];
    void tarjan(int x)
    {
        inz[x]=1;
        vis[x]=1;
        dep[x]=low[x]=++cnt;
        z[++top]=x;
        for(int i=head[x];i;i=nxt[i])
        {
            if(dep[to[i]]==0)
            {
                tarjan(to[i]);
                low[x]=min(low[x],low[to[i]]);
            }
            else if(inz[to[i]]!=0)
                low[x]=min(low[x],dep[to[i]]);
        }
        if(dep[x]==low[x])
        {
            ans++;
            int t;
            do
            {
                t=z[top--];
                neww[ans]++;
                f[t]=ans;
                inz[t]=0;
            }while(t!=x);
        }
    }

     九.KMP算法(以洛谷模板为例)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    int nxt[1000001],k,ans[1000001],cnt,l1,l2;
    char s1[1000001],s2[1000001];
    void getnxt()
    {
        for(int i=2;i<=l2;i++)
        {
            while(k!=0&&s2[i]!=s2[k+1])
                k=nxt[k];
            if(s2[i]==s2[k+1])
                k++;
            nxt[i]=k;
        }
    }
    void KMP()
    {
        for(int i=1;i<=l1;i++)
        {
            while(k!=0&&s1[i]!=s2[k+1])
                k=nxt[k];
            if(s1[i]==s2[k+1])
                k++;
            if(k==l2)
                ans[++cnt]=i-l2+1;
        }
    }
    int main()
    {
        scanf("%s%s",s1+1,s2+1);
        l1=strlen(s1+1);
        l2=strlen(s2+1);
        nxt[1]=0;
        getnxt();
        k=0;
        KMP();
        for(int i=1;i<=cnt;i++)
            printf("%d
    ",ans[i]);
        for(int i=1;i<=l2;i++)
            printf("%d ",nxt[i]);
    }

    十.高斯消元法

    #include<stdio.h>
    #include<math.h>
    #define eps 1e-8
    int n;
    double a[105][105],idx2;
    int main()
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
                scanf("%lf",&a[i][j]);
            scanf("%lf",&a[i][n]);
        }        
        for(int i=0;i<n;i++)
        {
            int idx=i;
            for(int j=i;j<n;j++)
                if(fabs(a[j][i]-a[idx][i])<=eps) 
                    idx=j;
            for(int j=0;j<=n;j++)
            {
                idx2=a[i][j];
                a[i][j]=a[idx][j];
                a[idx][j]=idx2;
            }
            if(fabs(a[i][i])<=eps)
            {
                printf("No Solution");
                return 0;
            }
            for(int j=i+1;j<=n;j++)
                a[i][j]/=a[i][i];
            for(int j=0;j<n;j++)
                if(i!=j)
                    for(int k=i+1;k<=n;k++)
                        a[j][k]-=a[j][i]*a[i][k];
        }
        for(int i=0;i<n;i++)
            printf("%.2lf
    ",a[i][n]);    
    }
  • 相关阅读:
    python批量安装包文件requirements.txt
    python→列表、元组、字典、集合对比整理表
    Python ddt+xlrd的使用
    input类型上传多个文件(selenium+Python)
    iframe切入切出问题,经常会碰到
    selenium+python 第一步启动火狐报错解决方案,已成功
    QTP从svn上载下来无法跑,解决
    函数可变参传值(python)
    关于python 函数参数
    Air Kiss
  • 原文地址:https://www.cnblogs.com/jiangminghong/p/9868662.html
Copyright © 2020-2023  润新知