zoukankan      html  css  js  c++  java
  • HGOI20190809 省常中互测2

      Problem A 时之终结

    构造一个含有$n$个节点的无重边无自环的有向图,

    使得从$1$出发,每一次经过一条$(u,v) (u < v)$的边到达节点$n$的方案恰好有$y$种。

    对于$100\%$的数据,输出的无向图顶点树$n leq 64 $给出的$y leq 10^{18}$

    Sol : 首先构造$63$个点的完全图,然后向第64个顶点连边,原问题等价于将$y$二进制拆分。

       这样构造可以获得满分:复杂度$O( {log_2}^2 n)$

    # include <bits/stdc++.h>
    # define int long long
    using namespace std;
    bool mp[65][65];
    signed main()
    {
        int y; scanf("%lld",&y); 
        int cnt=0;
        for (int i=1;i<=63;i++) for (int j=i+1;j<=63;j++) mp[i][j]=1,cnt++;
        for (int i=0;i<=63;i++) if ((y>>i)&1ll) mp[i+2][64]=1,cnt++;
        printf("64 %lld
    ",cnt);
        for (int i=1;i<=64;i++)
         for (int j=i+1;j<=64;j++)
          if (mp[i][j]) printf("%lld %lld 
    ",i,j);
        return 0;
    }
    A.cpp

      Problem B 博士之时

    $n$个节点,每个节点的度最多为$2$的图,共有$2$种不同的颜色,每一条相邻边都是不同色(0/1)的。

    求出有多少种可能的重排置换,使得每个一对原本没有通过某种颜色进行连接的节点,出现在了这种颜色的连接中。

    对于$100\%$的数据$nleq 2 imes 10^5$ , 图中每个点的度数最多为$2$。

    Sol : 图中所有节点的度数小于等于2的可能只有是环或者链,而整个图一定是由一些单独的环和单独的链和孤立的点组成的。

         考虑链的情况,相同长度的链是可以互相交换的,同时考虑含有奇数条边的链又可以中心对称翻转的,而含偶数条边的链不行。

         考虑环的情况,相同长度的环是可以相互交换的,同时考虑每个环是可以转动这个环中的节点数次的。

         所以,我们有下列算法。

       对于链,分含奇数条边的链和偶数条边的链的讨论。

    • 奇数条边的链(设长度为$i$的奇数条边有$j$条): $2^j imes j!$
    • 偶数条边的链(设长度为$i$的奇数条边有$j$条):$ j!$

       对于环,无需分奇数偶数讨论。

         设长度为$i$的环有$j$个:$j! imes i^j$ 

           设有$k$个孤立点,显然这些孤立点可以任意排列:$k!$

        将上述情况相乘就是合法的答案,如果用$n!$减去就是不合法的答案。

      复杂度是$O(n)$ 

    # include <bits/stdc++.h>
    # define int long long
    using namespace std;
    const int N=2e5+10,mo=1e9+7;
    struct rec{  int pre,to,w; rec() { w=-1; } }a[N<<1];
    bool vis[N];
    int du[N],head[N],jc[N],Pow2[N];
    int tot,n,m1,m2,cnt;
    bool flag;
    int col;
    map<int,int>circle,chain_even;
    map<pair<int,int>,int>chain_odd;
    int Pow(int x,int n)
    {
        int ans=1;
        while (n) {
            if (n&1) ans=ans*x%mo;
            x=x*x%mo;
            n>>=1;
        }
        return ans%mo;
    }
    void adde(int u,int v,int w)
    {
        a[++tot].pre=head[u];
        a[tot].to=v;
        a[tot].w=w;
        head[u]=tot;
    }
    void dfs1(int u)
    {
        vis[u]=1;
        for (int i=head[u];i;i=a[i].pre) {
            int v=a[i].to; if (vis[v]) continue;
            if (!flag) col=a[i].w,flag=1; 
            cnt++; dfs1(v);
        }
    }
    void dfs2(int u)
    {
        vis[u]=1;
        for (int i=head[u];i;i=a[i].pre) {
            int v=a[i].to; if (vis[v]) continue;
            cnt++; dfs2(v);
        }
    }
    signed main()
    {
        int num; scanf("%lld",&num);
        scanf("%lld%lld%lld",&n,&m1,&m2);
        for (int i=1;i<=m1;i++) {
            int u,v; scanf("%lld%lld",&u,&v);
            adde(u,v,0); adde(v,u,0);
            du[u]++; du[v]++;
        }
        for (int i=1;i<=m2;i++) {
            int u,v; scanf("%lld%lld",&u,&v);
            adde(u,v,1); adde(v,u,1);
            du[u]++; du[v]++;
        }
        
        jc[0]=1; for (int i=1;i<=200000;i++) jc[i]=jc[i-1]*i%mo;
        Pow2[0]=1; for (int i=1;i<=200000;i++) Pow2[i]=Pow2[i-1]*2%mo; 
        
        for (int i=1;i<=n;i++) if (!vis[i] && du[i]==1) {
            cnt=0; col=-1; flag=false; dfs1(i);  
            if (cnt&1) chain_odd[make_pair(cnt,col)]++;
            else chain_even[cnt]++;
        }
        for (int i=1;i<=n;i++) if (!vis[i] && du[i]==2) {
            cnt=1; dfs2(i);  circle[cnt]++;
        }
        int res=0;
        for (int i=1;i<=n;i++) if (!vis[i]) res++;
        
        int ret=jc[res]; map<int,int>::iterator it;
        for (it = circle.begin() ; it != circle.end() ; ++it) {
            int i=it->first,j=it->second;
            ret=ret*jc[j]%mo*Pow(i,j)%mo; 
        } 
        for (it = chain_even.begin(); it!=chain_even.end() ; ++it) {
            int i=it->first,j=it->second;
            ret=ret*jc[j]%mo;
        }
        map<pair<int,int>,int>::iterator it2;
        
        for (it2 = chain_odd.begin() ; it2 != chain_odd.end() ; ++it2) {
            pair<int,int> p=it2->first; int i=p.first,j=it2->second; 
            ret=ret*jc[j]%mo*Pow2[j]%mo;
        }
        
        int ans = ((jc[n] - ret) % mo + mo) % mo;
        printf("%lld
    ",ans); 
        
        return 0;
    }
    B.cpp

      Problem C 曾有两次

     给出无向连通图$G$,有$n$个点和$m$条边,

     对于每一个点,求删除一条边后这个点到$1$节点的距离可能的最大值

     对于$100\%$的数据满足,$nleq 2 imes 10^5 , m leq 5 imes 10^5$

     Sol: 删除的边一定是最短路树上该点和其父节点的连边。

      于是直接建出最短路树,然后依次考虑每一条非树边$(u,v)$

      对于链$u -> lca(u,v) $ 不含lca的所有点都可以先最短路树的叶子节点走,经过枚举的这一条边,然后从$v$节点走到根。

      对于链$v -> lca(u,v) $ 不含lca的所有点同理。

      这样对于在链上的一个节点$k$,那么对其用$dist(k,u) + w(u,v) + dist(1,v)$更新即可。

         注意到$dist(k,u)$ 这个可以表示为$dist(1,u) - dist(1,k)$ 原来的式子可以化为 $dist(1,u) - dist(1,k) + w(u,v) + dist(1,v) $

      只有$dist(1,k)$是定值,所以我们可以最后统一处理,我们只需要使用$dist(1,u)  + w(u,v) + dist(1,v) $来更新每个节点的答案即可。

      这就变成了在树上维护区间更新一个min值然后单点查询,直接使用树链剖分维护即可。

      复杂度是$O(m { log_2 }^2n )$

    # pragma GCC optimize(3) 
    # include <bits/stdc++.h>
    # define int long long 
    # define inf (1e14)
    using namespace std;
    const int N=2e5+10;
    const int M=5e5+10;
    struct rec{ int pre,to,w;}a[M<<1];
    struct edge{ int u,v,w;}rec[M<<1];
    int n,m,tot=1;
    int head[N],d[N],e[N],f[N],dep[N],size[N];
    int dfn[N],top[N],g[N][22];
    bool b[M<<1];
    vector<int>E[N];
    pair<int,int>pre[N];
    inline int read()
    {
        int X=0,w=0; char c=0;
        while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
        while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
        return w?-X:X;
    }
    void write(int x)
    {
        if (x>9) write(x/10);
        putchar('0'+x%10);
    }
    void adde(int u,int v,int w)
    {
        a[++tot].pre=head[u];
        a[tot].to=v; 
        a[tot].w=w;
        head[u]=tot;
    }
    struct node {
        int id,len;
    };
    struct cmp {
        bool operator () (node x,node y) {
            return x.len > y.len ;
        }
    };
    priority_queue<node,vector<node>,cmp>q;
    bool vis[N];
    void dijkstra(int s)
    {
        memset(vis,false,sizeof(vis));
        memset(d,0x3f,sizeof(d));
        d[s]=0; q.push((node){s,0});
        while (!q.empty()) {
            node u=q.top();q.pop();
            if (vis[u.id]) continue;
            vis[u.id]=1;
            for (int i=head[u.id];i;i=a[i].pre) {
                int v=a[i].to,w=a[i].w;
                if (d[v]-w>d[u.id]) {
                    e[v]=i; pre[v]=make_pair(u.id,w); d[v]=d[u.id]+w; 
                    q.push((node){v,d[v]});
                }
            }
        }
    }
    void dfs1(int u,int fa)
    {
        f[u]=fa; dep[u]=dep[fa]+1; size[u]=1;
        for (int i=0;i<E[u].size();i++) {
            int v=E[u][i]; if (v==fa) continue;
            dfs1(v,u); size[u]+=size[v];
        }
    }
    void dfs2(int u,int fa,int tp)
    {
        dfn[u]=++dfn[0]; top[u]=tp; 
        int son=-1;
        for (int i=0;i<E[u].size();i++) {
            int v=E[u][i]; if (v==fa) continue;
            if (son==-1||size[v]>size[son]) son=v;
        }
        if (son!=-1) dfs2(son,u,tp);
        for (int i=0;i<E[u].size();i++) {
            int v=E[u][i]; if (v==fa) continue;
            if (v!=son) dfs2(v,u,v);
        }
    }
    # define ls (x<<1)
    # define rs (x<<1|1)
    # define lson ls,l,mid
    # define rson rs,mid+1,r
    # define mid (l+r>>1)
    struct Segmengt_Tree{
        int tag,ret;
        Segmengt_Tree() { tag=-1; ret=inf;}
    }tr[N<<2];
    void down(int x)
    {
        if (tr[x].tag==-1) return;
        tr[ls].ret=min(tr[ls].ret,tr[x].tag);
        tr[rs].ret=min(tr[rs].ret,tr[x].tag);
        tr[ls].tag=(tr[ls].tag==-1)?tr[x].tag:min(tr[x].tag,tr[ls].tag);
        tr[rs].tag=(tr[rs].tag==-1)?tr[x].tag:min(tr[x].tag,tr[rs].tag);
        tr[x].tag=-1; 
    }
    void update(int x,int l,int r,int opl,int opr,int d)
    {
        if (opl<=l &&r<=opr) {
            if (tr[x].tag==-1) tr[x].tag=d;
            else tr[x].tag=min(tr[x].tag,d);
            tr[x].ret=min(tr[x].ret,d);
            return;
        }
        down(x);
        if (opl<=mid) update(lson,opl,opr,d);
        if (opr>mid) update(rson,opl,opr,d);
        tr[x].ret=min(tr[ls].ret,tr[rs].ret); 
    }
    int query(int x,int l,int r,int opl,int opr)
    {
        if (opl<=l&&r<=opr) return tr[x].ret;   
        down(x);
        int ret=inf;
        if (opl<=mid) ret=min(ret,query(lson,opl,opr));
        if (opr>mid) ret=min(ret,query(rson,opl,opr));
        return ret;
    }
    int lca(int u,int v)
    {
        if (dep[u]<dep[v]) swap(u,v);
        for (int i=21;i>=0;i--)
         if (dep[g[u][i]]>=dep[v]) u=g[u][i];
        if (u==v) return u;
        for (int i=21;i>=0;i--)
         if (g[u][i]!=g[v][i]) u=g[u][i],v=g[v][i];
        return g[u][0];  
    }
    void update(int u,int v,int d)
    {
        int f1=top[u],f2=top[v];
        while (f1!=f2) {
            if (dep[f1]<dep[f2]) swap(f1,f2);
            update(1,1,n,dfn[f1],dfn[u],d);
            u=f[f1]; f1=top[u];
        }
        if (dep[u]<dep[v]) swap(u,v);
        update(1,1,n,dfn[v]+1,dfn[u],d);
    }
    int query(int x){
        return query(1,1,n,dfn[x],dfn[x]);
    }
    main()
    {
        int num=read();
        n=read();m=read();
        for (int i=1;i<=m;i++) {
            int u=read(),v=read(),w=read();
            adde(u,v,w); rec[tot]=(edge){u,v,w}; adde(v,u,w);
        }
        dijkstra(1);
        for (int i=2;i<=n;i++) {
            b[e[i]]=b[e[i]^1]=1; 
            E[i].push_back(pre[i].first);
            E[pre[i].first].push_back(i);
        }
        dfs1(1,0); dfs2(1,0,0);
        for (int i=1;i<=n;i++) g[i][0]=f[i];
        for (int i=1;i<=21;i++) for (int j=1;j<=n;j++) g[j][i]=g[g[j][i-1]][i-1];
        for (int i=2;i<=tot;i+=2)
         if (!b[i]) {
            int u=rec[i].u,v=rec[i].v,w=rec[i].w,l=lca(u,v);
            update(u,l,d[v]+w+d[u]); update(v,l,d[u]+w+d[v]);
         }
        putchar('0'); putchar(' ');
        for (int i=2;i<=n;i++) { 
            int t=query(i);
            if (t>=inf) putchar('-'),putchar('1');
            else write(t-d[i]);
            putchar(' ');
        } 
        putchar('
    ');
        return 0;
    }
    C.cpp
  • 相关阅读:
    结构体 和 类 的区别
    运算符重载
    迭代器
    HttpClient 同时上传多个文件及参数, 同时利用 Web Api 接收
    JS 上传图片时实现预览
    web api 如何通过接收文件流的方式,接收客户端及前端上传的文件
    同时上传参数及图片到 Web Api
    jsp jstl标签库核心标签
    jsp jstl的使用
    jsp 简单标签开发
  • 原文地址:https://www.cnblogs.com/ljc20020730/p/11328170.html
Copyright © 2011-2022 走看看