• 牛客NOIP暑期七天营-提高组1


    A思路:排个序建立最短路树即可,可以双指针实现。

    考察:贪心,构造。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=2000010;
    struct in{
        int x,id;
        bool friend operator <(in w,in v){ if(w.x==v.x) return w.id<v.id; return w.x<v.x; }
    }s[maxn];
    int a[maxn],b[maxn],c[maxn],tot;
    int q[maxn],head,tail;
    int main()
    {
        int N,M;
        scanf("%d%d",&N,&M);
        rep(i,1,N) scanf("%d",&s[i].x),s[i].id=i;
        sort(s+1,s+N+1);
        q[++head]=1;
        rep(i,2,N) {
            while(head>tail&&s[i].x-s[q[tail+1]].x>M) tail++;
            if(head>tail){
                a[i]=s[q[tail+1]].id;
                b[i]=s[i].id;
                c[i]=s[i].x-s[q[tail+1]].x;
            }
            q[++head]=i;
            if(c[i]==0) {
                puts("-1");
                return 0;
            }
        }
        printf("%d
    ",N-1);
        rep(i,2,N) printf("%d %d %d
    ",a[i],b[i],c[i]);
        return 0;
    }

    B:显然最大值取决于a[],出现的最高位不同的那一位,假设有最高位的分到A组,不然分到B组,分组后,各取一个x,y,那么ans=min(x^y),这个可以字典树实现。

    比较常规。 但是比赛的时候我以为字典树空间不够只能得80分。所以写了分治, 分治复杂度也是O(60*N)的,而且感觉比字典树保险,实现就是每一层,继续分组。

    考察:贪心,字典树求最小异或。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=2000010;
    ll a[maxn],b[maxn],c[maxn],ans=0;
    void solve(int p,int L1,int R1,int L2,int R2,ll sum)
    {if(p==-1){
            ans=min(ans,sum);
            return ;
        }
        int t1=0,t2=0;
        for(int i=L1;i<=R1;i++){
            if(a[i]&(1LL<<p)) b[++t1]=a[i];
            else c[++t2]=a[i];
        }
        rep(i,1,t1) a[L1+i-1]=b[i];
        rep(i,1,t2) a[L1+t1+i-1]=c[i];
     
        int t3=0,t4=0;
        for(int i=L2;i<=R2;i++){
            if(a[i]&(1LL<<p)) b[++t3]=a[i];
            else c[++t4]=a[i];
        }
        rep(i,1,t3) a[L2+i-1]=b[i];
        rep(i,1,t4) a[L2+t3+i-1]=c[i];
        int F=0;
        if(t1&&t3) F=1,solve(p-1,L1,L1+t1-1,L2,L2+t3-1,sum);
        if(t2&&t4) F=1,solve(p-1,L1+t1,R1,L2+t3,R2,sum);
        if(F) return ;
        solve(p-1,L1,R1,L2,R2,sum+(1LL<<p));
    }
    int main()
    {
        int N; scanf("%d",&N);
        rep(i,1,N) scanf("%lld",&a[i]);
        int p=-1;
        for(int i=60;i>=0;i--){
            int tot=0;
            rep(j,1,N) if(a[j]&(1LL<<i)) tot++;
            if(tot!=0&&tot!=N) {
                p=i; break;
            }
        }
        if(p!=-1){
            int t1=0,t2=0; ans=1LL<<61;
            rep(i,1,N) {
                if(a[i]&(1LL<<p)) b[++t1]=a[i];
                else c[++t2]=a[i];
            }
            rep(i,1,t1) a[i]=b[i];
            rep(i,1,t2) a[t1+i]=c[i];
            solve(p-1,1,t1,t1+1,N,1LL<<p);
        }
        printf("%lld
    ",ans);
        return 0;
    }

    C:求最小字典序下的公共路径长度,由于N比较小,显然就是枚举每个点为根,然后最小字典序的  Σ最短路树LCA到根的距离,预料到码量比较长,就写了个floyd骗分,LCA也直接写的倍增(估计写tarjan会快个10倍),70分水过。   字典序那里先排个序,然后记忆化搜索实线。

    考察:最短路,LCA,保证字典序。

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define mp make_pair
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int inf=1e9;
    const int maxn=2001;
    int dis[maxn][maxn];
    int Laxt[maxn],Next[6001],To[6001],len[6001],cnt;
    int a[6001],b[6001],fa[maxn][12],ans[6001],dep[maxn],N,Q;
    bool vis[maxn]; int ind[maxn];
    vector<int>G[maxn];
    void add(int u,int v,int w)
    {
        Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; len[cnt]=w;
    }
    int LCA(int u,int v)
    {
        if(dep[u]<dep[v]) swap(u,v);
        for(int i=11;i>=0;i--) {
            if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];
        }
        if(u==v) return u;
        for(int i=11;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
        return fa[u][0];
    }
    set<pii>s;
    void dfs(int u,int f)
    {
        if(vis[u]) return ;
        vis[u]=1; fa[u][0]=f; dep[u]=dep[f]+1;
        for(int i=0;i<G[u].size();i++) dfs(G[u][i],u);
    }
    void solve(int p)
    {
        rep(i,1,N) vis[i]=0;
        rep(i,1,N) G[i].clear();
        rep(i,1,N)
         for(int j=Laxt[i];j;j=Next[j]){
            if(dis[p][i]+len[j]==dis[p][To[j]]) G[i].push_back(To[j]);
         }
        rep(i,1,N) sort(G[i].begin(),G[i].end());
        dfs(p,0);
        rep(i,1,11) rep(j,1,N) fa[j][i]=fa[fa[j][i-1]][i-1];
        rep(i,1,Q){
             if(!vis[a[i]]||!vis[b[i]]) continue;
             ans[i]=max(ans[i],dis[p][LCA(a[i],b[i])]);
        }
    }
    int main()
    {
        int M,u,v,w;
        scanf("%d%d%d",&N,&M,&Q);
        rep(i,1,Q) ans[i]=-1;
        rep(i,1,N) rep(j,1,N) dis[i][j]=inf;
        rep(i,1,N) dis[i][i]=0;
        rep(i,1,M) {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            dis[u][v]=min(dis[u][v],w);
        }
        rep(i,1,Q) scanf("%d%d",&a[i],&b[i]);
        rep(k,1,N)
         rep(i,1,N)
          if(dis[i][k]!=inf)
            rep(j,1,N)
              dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
        rep(i,1,N) solve(i);
        rep(i,1,Q) printf("%d
    ",ans[i]);
        return 0;
    }

     改为dijstra变为90分了:

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int inf=1e9;
    const int maxn=2001;
    int dis[maxn][maxn];  bool vis[maxn];
    int Laxt[maxn],Next[6001],To[6001],len[6001],cnt;
    int a[6001],b[6001],ans[6001],dep[maxn],N,Q;
    vector<int>G[maxn],P[maxn];
    int son[maxn],sz[maxn],Tp[maxn],fa[maxn];
    void add(int u,int v,int w)
    {
        Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; len[cnt]=w;
    }
    void dfs1(int u,int f)
    {
        sz[u]=1; son[u]=0; dep[u]=dep[f]+1; fa[u]=f;
        for(int i=0;i<P[u].size();i++){
            if(!son[P[u][i]]) {
                int v=P[u][i];
                dfs1(v,u); sz[u]+=sz[v];
                if(sz[v]>sz[son[u]]) son[u]=v;
            }
        }
    }
    void dfs2(int u,int tp)
    {
        Tp[u]=tp;
        if(son[u]) dfs2(son[u],tp);
        for(int i=0;i<P[u].size();i++){
            if(P[u][i]!=son[u])
                 dfs2(P[u][i],P[u][i]);
        }
    }
    int LCA(int u,int v)
    {
        while(Tp[u]^Tp[v]) dep[Tp[u]]<dep[Tp[v]]?v=fa[Tp[v]]:u=fa[Tp[u]];
        return dep[u]<dep[v]?u:v;
    }
    void dfs(int u,int f)
    {
        if(vis[u]) return ;
        vis[u]=1; P[f].push_back(u);
        for(int i=0;i<G[u].size();i++) dfs(G[u][i],u);
    }
    struct ww{
        int dis,u;
        bool friend operator <(ww w,ww v){ return w.dis>v.dis; }
    };
    priority_queue<ww>q; int inq[maxn];
    void SPFA(int S)
    {
        rep(i,1,N) dis[S][i]=inf; dis[S][S]=0;
        q.push(ww{0,S});
        while(!q.empty()){
            int u=q.top().u; q.pop(); inq[u]=0;
            for(int i=Laxt[u];i;i=Next[i]) {
                int v=To[i];
                if(dis[S][v]>dis[S][u]+len[i]){
                    dis[S][v]=dis[S][u]+len[i];
                    if(!inq[v]) inq[v]=1,q.push(ww{dis[S][v],v});
                }
            }
        }
    }
    void solve(int p)
    {
        rep(i,1,N) vis[i]=son[i]=0;
        rep(i,0,N) G[i].clear(),P[i].clear();
        rep(i,1,N)
         for(int j=Laxt[i];j;j=Next[j]){
            if(dis[p][i]+len[j]==dis[p][To[j]]) G[i].push_back(To[j]);
        }
        rep(i,1,N) sort(G[i].begin(),G[i].end());
        dfs(p,0); dfs1(p,0); dfs2(p,p);
        rep(i,1,Q){
             if(!vis[a[i]]||!vis[b[i]]) continue;
             ans[i]=max(ans[i],dis[p][LCA(a[i],b[i])]);
        }
    }
    int main()
    {
        int M,u,v,w;
        scanf("%d%d%d",&N,&M,&Q);
        rep(i,1,Q) ans[i]=-1;
        rep(i,1,N) rep(j,1,N) dis[i][j]=inf;
        rep(i,1,N) dis[i][i]=0;
        rep(i,1,M) {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
        }
        rep(i,1,Q) scanf("%d%d",&a[i],&b[i]);
        rep(i,1,N) SPFA(i);
        rep(i,1,N) solve(i);
        rep(i,1,Q) printf("%d
    ",ans[i]);
        return 0;
    }
    View Code

    按照题解写的,还是90分:

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int inf=1e9;
    const int maxn=2001;
    int dis[maxn][maxn];  bool vis[maxn];
    int Laxt[maxn],Next[6001+maxn],To[6001+maxn],len[6001+maxn],cnt;
    int a[6001],b[6001],ans[6001],dep[maxn],N,Q;
    vector<int>G[maxn],P[maxn];
    int son[maxn],sz[maxn],Tp[maxn],fa[maxn];
    void add(int u,int v,int w)
    {
        Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; len[cnt]=w;
    }
    void dfs1(int u,int f)
    {
        sz[u]=1; son[u]=0; dep[u]=dep[f]+1; fa[u]=f;
        for(int i=0;i<P[u].size();i++){
            if(!son[P[u][i]]) {
                int v=P[u][i];
                dfs1(v,u); sz[u]+=sz[v];
                if(sz[v]>sz[son[u]]) son[u]=v;
            }
        }
    }
    void dfs2(int u,int tp)
    {
        Tp[u]=tp;
        if(son[u]) dfs2(son[u],tp);
        for(int i=0;i<P[u].size();i++){
            if(P[u][i]!=son[u])
                 dfs2(P[u][i],P[u][i]);
        }
    }
    int LCA(int u,int v)
    {
        while(Tp[u]^Tp[v]) dep[Tp[u]]<dep[Tp[v]]?v=fa[Tp[v]]:u=fa[Tp[u]];
        return dep[u]<dep[v]?u:v;
    }
    void dfs(int u,int f)
    {
        if(vis[u]) return ;
        vis[u]=1; P[f].push_back(u);
        for(int i=0;i<G[u].size();i++) dfs(G[u][i],u);
    }
    struct ww{
        int dis,u;
        bool friend operator <(ww w,ww v){ return w.dis>v.dis; }
    };
    priority_queue<ww>q; int inq[maxn],h[maxn];
    void SPFA(int S)
    {
        rep(i,0,N) dis[S][i]=inf; dis[S][S]=0;
        q.push(ww{0,S});
        while(!q.empty()){
            int u=q.top().u; q.pop(); inq[u]=0;
            for(int i=Laxt[u];i;i=Next[i]) {
                int v=To[i];
                if(dis[S][v]>dis[S][u]+len[i]){
                    dis[S][v]=dis[S][u]+len[i];
                    if(!inq[v]) inq[v]=1,q.push(ww{dis[S][v],v});
                }
            }
        }
        if(S==0) {
            rep(i,1,N) h[i]=dis[S][i];
            rep(i,1,N) for(int j=Laxt[i];j;j=Next[j]) len[j]=len[j]+h[i]-h[To[j]];
        }
        else {
            rep(i,1,N) if(dis[S][i]!=inf) dis[S][i]=dis[S][i]+h[i]-h[S];
        }
    }
    void solve(int p)
    {
        rep(i,1,N) vis[i]=son[i]=0;
        rep(i,0,N) G[i].clear(),P[i].clear();
        rep(i,1,N)
         for(int j=Laxt[i];j;j=Next[j]){
            if(dis[p][i]+len[j]-h[i]+h[To[j]]==dis[p][To[j]]) G[i].push_back(To[j]);
        }
        rep(i,1,N) sort(G[i].begin(),G[i].end());
        dfs(p,0); dfs1(p,0); dfs2(p,p);
        rep(i,1,Q){
             if(!vis[a[i]]||!vis[b[i]]) continue;
             ans[i]=max(ans[i],dis[p][LCA(a[i],b[i])]);
        }
    }
    int main()
    {
        int M,u,v,w;
        scanf("%d%d%d",&N,&M,&Q);
        rep(i,1,Q) ans[i]=-1;
        rep(i,1,N) rep(j,1,N) dis[i][j]=inf;
        rep(i,1,N) dis[i][i]=0;
        rep(i,1,N) add(0,i,0);
        rep(i,1,M) {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
        }
        rep(i,1,Q) scanf("%d%d",&a[i],&b[i]);
        rep(i,0,N) SPFA(i);
        rep(i,1,N) solve(i);
        rep(i,1,Q) printf("%d
    ",ans[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    redhat,centos Linux常用命令LS之常用功能
    人生信用卡
    如何让Redhat Linux启动时进入字符终端模式(不进入XWindow)
    OpenJDK和JDK区别
    Linux rpm 命令参数使用详解[介绍和应用]
    linux 的vim命令详解
    centos6.4安装javajdk1.8
    samba服务器 实现Linux与windows 文件共享
    SELinux 宽容模式(permissive) 强制模式(enforcing) 关闭(disabled) 几种模式之间的转换
    linux学习之 Linux下的Eclipse安装
  • 原文地址:https://www.cnblogs.com/hua-dong/p/11376592.html
Copyright © 2020-2023  润新知