zoukankan      html  css  js  c++  java
  • BestCoder Round #74

    身败名裂啊。。。。。。

    T1WA了半天,30min才A。

    T2又WA了一发,然后Hack刚2min就被别人叉了。

    T3做完后最后40min不知所措。

    去叉别人,看到一个人写D题判m=0很奇怪,随手把他叉了:

    1

    3 0

    然后发现,标程输出1.

    奥妙重重

    嘿嘿嘿,我竟然又去叉了吉利。

    T1的SB错误是,答案可能是|x-y|。

    T2的SB错误是,一个[1,10^5]的数异或[1,10^5]的数可能是[1,131072]的数。

    T1 Shortest Path

    x到y的路径可能有几种:
    1.x->y

    2.x->i->j>y

    其中i和j是新边里的节点(称为关键节点)

    将六个关键点连起来跑一下Floyd,然后每次询问时枚举一下i,j。

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<map>
    #include<algorithm>
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    using namespace std;
    inline int read() {
        int x=0,f=1;char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int maxn=100010;
    int n,m,u[5],v[5],A[10],cnt;
    int W[10][10];
    map<int,int> M;
    int find(int x) {
        if(!M.count(x)) M[x]=++cnt,A[cnt]=x;
        return M[x];
    }
    const int mod=1000000007;
    int main() {
        dwn(T,read(),1) {
            n=read();m=read();M.clear();cnt=0;
            rep(i,1,6) rep(j,1,6) W[i][j]=100000000;
            rep(i,1,6) W[i][i]=0;
            rep(i,1,3) u[i]=read(),v[i]=read(),W[find(u[i])][find(v[i])]=W[find(v[i])][find(u[i])]=1;
            rep(i,1,cnt) rep(j,1,cnt) W[i][j]=min(W[i][j],abs(A[i]-A[j]));
            rep(k,1,cnt) rep(i,1,cnt) rep(j,1,cnt) W[i][j]=min(W[i][j],W[i][k]+W[k][j]);
            long long res=0;
            rep(i,1,m) {
                int x=read(),y=read(),ans=abs(x-y);
                rep(k,1,cnt) rep(j,1,cnt) ans=min(ans,abs(A[k]-x)+abs(A[j]-y)+W[k][j]);
                (res+=(long long)i*ans)%=mod;
            }
            printf("%I64d
    ",res);
        }
        return 0;
    }
    View Code

    T2 Transform

    x -> y  <=> 0 -> x xor y

    所以从0BFS一下就好了。

    然后应该搜到[1,131072]。QAQ(AQ)*

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    #include<queue>
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    using namespace std;
    inline int read() {
        int x=0,f=1;char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int maxn=300010;
    const int mod=1000000007;
    typedef long long ll;
    int n,m,A[maxn],vis[maxn],d[maxn];
    queue<int> Q;
    void bfs() {
        memset(vis,0,sizeof(vis));d[0]=0;vis[0]=1;Q.push(0);
        while(!Q.empty()) {
            int x=Q.front();Q.pop();
            rep(i,0,20) {
                int v=x^(1<<i);
                if(v<=300000&&!vis[v]) {
                    vis[v]=1;d[v]=d[x]+1;Q.push(v);
                }
            }
            rep(i,1,n) {
                int v=x^A[i];
                if(v<=300000&&!vis[v]) {
                    vis[v]=1;d[v]=d[x]+1;Q.push(v);
                }
            }
        }
    }
    int main() {
        dwn(T,read(),1) {
            n=read();m=read();
            rep(i,1,n) A[i]=read();
            bfs();ll ans=0;
            rep(i,1,m) (ans+=(ll)i*d[read()^read()])%=mod;
            printf("%I64d
    ",ans);
        }
        return 0;
    }
    View Code

    T3 Toposort

    我们逐位考虑,那么我们需要一个数据结构完成这样的功能。

    1.找到当前权值<=k的最小节点。

    2.将一个节点的权值-1。

    显然线段树就行了。

    我懒得写线段树,于是STL大法好。

    用一个堆来维护一下在某次操作前权值<=k的节点,不行就把它踢出去。

    然后拓扑的时候再判判能不能扔到堆里。

    因为最多有n+m个节点进入堆,所以时间复杂度为O((n+m)logn)。

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<queue>
    #include<algorithm>
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    using namespace std;
    inline int read() {
        int x=0,f=1;char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int mod=1000000007;
    const int maxn=100010;
    const int maxm=200010;
    typedef long long ll;
    int n,m,k,first[maxn],Next[maxm],to[maxm],in[maxn],is[maxn],e;
    void AddEdge(int u,int v) {
        to[++e]=v;Next[e]=first[u];first[u]=e;in[v]++;
    }
    int main() {
        dwn(T,read(),1) {
            n=read();m=read();k=read();
            rep(i,1,n) in[i]=first[i]=is[i]=0;e=0;
            rep(i,1,m) {
                int u=read(),v=read();
                AddEdge(u,v);
            }
            priority_queue<int> Q;
            rep(i,1,n) if(in[i]<=k) is[i]=1,Q.push(-i);
            ll ans=0;
            rep(j,1,n) {
                int x;
                while(Q.size()) {
                    x=-Q.top();Q.pop();is[x]=0;
                    if(in[x]<=k) break;
                }
                (ans+=(ll)j*x)%=mod;k-=in[x];in[x]=0;is[x]=1;
                for(int i=first[x];i;i=Next[i]) if(in[to[i]]) {
                    in[to[i]]--;
                    if(in[to[i]]<=k&&!is[to[i]]) is[to[i]]=1,Q.push(-to[i]);
                }
            }
            printf("%I64d
    ",ans);
        }
        return 0;
    }
    View Code

    T4 Deletion

    比赛时并没有想出来QAQ(AQ)*

    这道题想法很妙,考虑题目说的“要求选出来的边构成的子图的每个连通块最多只有一个环”其实就是环套树。

    而如果对一个无向图进行定向,满足所有节点的出边最多只有1,那么这个无向图可以一次选出。

    所以问题转化成对一个无向图进行定向,让出边最多的节点出度最少,那么二分答案后就是一个分配模型了。

    #include<cstdio>
    #include<cctype>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define ren for(int i=first[x];i!=-1;i=Next[i])
    using namespace std;
    typedef long long ll;
    inline int read() {
        int x=0,f=1;char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int maxn=5010;
    const int maxm=100010;
    const int inf=1e9;
    struct Dinic {
        int n,m,s,t,first[maxn],Next[maxm];
        void init(int n) {
            m=0;this->n=n;
            memset(first,-1,sizeof(first));
        }
        struct Edge {int from,to,flow;}edges[maxm];
        void AddEdge(int u,int v,int w) {
            edges[m]=(Edge){u,v,w};Next[m]=first[u];first[u]=m++;
            edges[m]=(Edge){v,u,0};Next[m]=first[v];first[v]=m++;
        }
        int d[maxn],vis[maxn],cur[maxn];
        int BFS() {
            memset(vis,0,sizeof(vis));
            queue<int> Q;Q.push(s);vis[s]=1;
            while(!Q.empty()) {
                int x=Q.front();Q.pop();cur[x]=first[x];
                ren {
                    Edge& e=edges[i];
                    if(!vis[e.to]&&e.flow) {
                        vis[e.to]=1;
                        d[e.to]=d[x]+1;
                        Q.push(e.to);
                    }
                }
            }
            return vis[t];
        }
        int DFS(int x,int a) {
            if(x==t||!a) return a;
            int flow=0,f;
            for(int& i=cur[x];i!=-1;i=Next[i]) {
                Edge& e=edges[i];
                if(d[e.to]==d[x]+1&&(f=DFS(e.to,min(a,e.flow)))) {
                    e.flow-=f;edges[i^1].flow+=f;
                    a-=f;flow+=f;if(!a) break;
                }
            }
            return flow;
        }
        int solve(int s,int t) {
            this->s=s;this->t=t;int flow=0;
            while(BFS()) flow+=DFS(s,inf);
            return flow;
        }
    }sol;
    int n,m,u[maxn],v[maxn];
    int check(int x) {
        int s=n+m+1,t=n+m+2;sol.init(t);
        rep(i,1,n) sol.AddEdge(s,i,x);
        rep(i,1,m) sol.AddEdge(i+n,t,1);
        rep(i,1,m) sol.AddEdge(u[i],i+n,1),sol.AddEdge(v[i],i+n,1);
        return sol.solve(s,t)==m;
    }
    void solve() {
        n=read();m=read();
        rep(i,1,m) u[i]=read(),v[i]=read();
        if(!m) {puts("0");return;}
        int l=1,r=m,mid;
        while(l<r) if(check(mid=l+r>>1)) r=mid; else l=mid+1;
        printf("%d
    ",l);
    }
    int main() {
        dwn(T,read(),1) solve();
        return 0;
    }
    View Code
  • 相关阅读:
    27. Remove Element
    26. Remove Duplicates from Sorted Array
    643. Maximum Average Subarray I
    674. Longest Continuous Increasing Subsequence
    1. Two Sum
    217. Contains Duplicate
    448. Find All Numbers Disappeared in an Array
    566. Reshape the Matrix
    628. Maximum Product of Three Numbers
    UVa 1349 Optimal Bus Route Design (最佳完美匹配)
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5248571.html
Copyright © 2011-2022 走看看