jzoj5895. 【NOIP2018模拟10.5】旅游

版权声明:本人初三蒟蒻一只,欢迎各位大佬来点评。 https://blog.csdn.net/HiChocolate/article/details/82945263

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

在这里插入图片描述

题解

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

猜你喜欢

转载自blog.csdn.net/HiChocolate/article/details/82945263