zoukankan      html  css  js  c++  java
  • jzoj5895. 【NOIP2018模拟10.5】旅游

    Description

    在这里插入图片描述

    Input

    在这里插入图片描述
    在这里插入图片描述

    Output

    在这里插入图片描述

    Sample Input

    6 10
    4 6
    4 5
    3 6
    5 2
    3 2
    1 2
    3 4
    6 1
    2 4
    1 3

    Sample Output

    2132

    Data Constraint

    在这里插入图片描述

    题解

    看到这道题,我们想到了什么?
    欧拉回路!
    欧拉回路指在一个图中,从一个点开始是否可以经过每条边恰好一次最后回到起点。
    然后,对于一个无向图,只要每一个点的度数为偶数则表示:从任意一个点出发都可以找到至少一种方案使得——经过每条边恰好一次最后回到起点。
    所以说我们就要把题目给的图弄成欧拉回路。
    怎么弄?
    我们发现,对于每一个点的度数为偶数或奇数(废话),而且奇数的点的个数为偶数个(显然)。
    所以说,我们根据某些神奇的东西,可以发现——
    奇数点两两匹配后,在两个匹配的点之间找到一条最短的路,作为一条新的路,这样就消除了这两个点的度数为奇数的情况。
    (新的路等价于重复走这一条最短的路。)
    怎么匹配?怎么找最短路?
    我们发现,对于两个点之间一条路的代价“2n2^n”,我们找到它们的另一条路的代价“2p[i]sum2^{p[i]}”,且p[i]<n.
    那么就是说后者比前者更优。“2n&gt;2n1+2n2++212^n&gt;2^{n-1}+2^{n-2}+……+2^1
    那么我们就对于编号最小生成树即可。
    这样对于两个点之间最短距离就为树上的距离,证明显然。
    那说到底,怎么匹配?
    我们发现对于一棵树,树上很多的点之间两两匹配。
    最优方案中,任何两组匹配的路径不会重复走同一条路。
    证明我不会
    这样说来,每一条路径就有两种情况——
    1、被经过一次,要加入答案。
    2、不被经过,不加入答案。
    那么我们每次指定一条边,如果它删除后两颗树上关键点的数量都为奇数,
    那么代表这条边要被经过一次。
    为什么?因为两颗树中两点两两匹配都剩一个点,这剩下的点就要经过这条边互相匹配了。
    最后,答案再加上i=1n2isum_{i=1}^n2^i即可。

    uses math;
    const up=500000;
    var
            i,j,k,l,n,m,tot,gs,xx,yy:longint;
            op,ans,answer:int64;
            mo:int64=998244353;
            x,y,p:array[1..up] of longint;
            edge,f:array[1..up] of longint;
            tov,next,last,val:array[1..2*up] of longint;
            v,id,pre,fa,top,son,siz,dep:array[1..up] of longint;
            jl:array[0..up] of longint;
            tree:array[1..4*up] of longint;
            flag,dp:array[1..up] of longint;
    procedure insert(x,y,z:longint);
    begin
            inc(tot);
            tov[tot]:=y;
            next[tot]:=last[x];
            last[x]:=tot;
            val[tot]:=z;
    end;
    function getfather(x:longint):longint;
    begin
            if f[x]=x then exit(f[x]);
            f[x]:=getfather(f[x]);
            exit(f[x]);
    end;
    procedure dp1(v,fa:longint);
    var
            i,j,k,l:longint;
    begin
            dp[v]:=flag[v];
            i:=last[v];
            while i>0 do
            begin
                    if tov[i]<>fa then
                    begin
                            dp1(tov[i],v);
                            dp[v]:=dp[v]+dp[tov[i]];
                    end;
                    i:=next[i];
            end;
    end;
    procedure dp2(v,fa:longint);
    var
            i,j,k,l:longint;
    begin
            i:=last[v];
            while i>0 do
            begin
                    if tov[i]<>fa then
                    begin
                            if dp[tov[i]] mod 2=1 then
                            begin
                                    answer:=answer+val[i];
                            end;
                            dp2(tov[i],v);
                    end;
                    i:=next[i];
            end;
    end;
    begin
            assign(input,'travel.in');reset(input);
            assign(output,'travel.out');rewrite(output);
            readln(n,m);
            op:=1;
            for i:=1 to m do
            begin
                    readln(x[i],y[i]);
                    inc(edge[x[i]]);
                    inc(edge[y[i]]);
                    op:=(op*2) mod mo;
                    p[i]:=op;
            end;
            for i:=1 to n do f[i]:=i;
            for i:=1 to m do
            begin
                    xx:=getfather(x[i]);
                    yy:=getfather(y[i]);
                    if xx<>yy then
                    begin
                            f[xx]:=yy;
                            insert(x[i],y[i],p[i]);
                            insert(y[i],x[i],p[i]);
                            inc(k);
                    end;
                    if k=n-1 then break;
            end;
            j:=0;
            op:=0;
            for i:=1 to n do
            begin
                    if edge[i] mod 2=1 then
                    begin
                            inc(j);
                            if op=0 then
                            begin
                                    j:=1;
                                    jl[j]:=i;
                            end
                            else
                            begin
                                    inc(j);
                                    jl[j]:=i;
                            end;
                            flag[jl[j]]:=1;
                    end;
            end;
            op:=j;
            dp1(1,0);
            dp2(1,0);
            op:=1;
            for i:=1 to m do
            begin
                    op:=(op*2) mod mo;
                    answer:=(answer+op) mod mo;
            end;
            writeln(answer);
    end.
    
    我活在这夜里。无论周围多么黑暗,我都要努力发光!我相信着,终有一天,我会在这深邃的夜里,造就一道最美的彩虹。
  • 相关阅读:
    PHPstrom常用快捷键
    PHP中实现中文字串截取无乱码的方法
    PHP中如何配置smarty框架实现PHP代码和HTML代码分离
    HTML5新增的语义标签和IE版本低的兼容性问题
    [转]mysql查看所有触发器以及存储过程等操作集合
    [转]CentOS 6.5忘记root密码,怎么办?
    完美世界国际版Debug
    Jacob 官方项目
    确保已安装并运行winrm3.0 并打开了所需的防火墙端口
    [转]关于微信JSSDK中遇到的“invalid signature”的天坑
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11148389.html
Copyright © 2011-2022 走看看