1063: [Noi2008]道路设计 - BZOJ

Description

Z 国坐落于遥远而又神奇的东方半岛上,在小Z 的统治时代公路成为这里主要的交通手段。Z 国共有n 座城市,一些城市之间由双向的公路所连接。非常神奇的是Z 国的每个城市所处的经度都不相同,并且最多只和一个位于它东边的城市直接通过公路相连。Z 国的首都是Z 国政治经济文化旅游的中心,每天都有成千上万的人从Z 国的其他城市涌向首都。 为了使Z 国的交通更加便利顺畅,小Z 决定在Z 国的公路系统中确定若干条规划路线,将其中的公路全部改建为铁路。 我们定义每条规划路线为一个长度大于1 的城市序列,每个城市在该序列中最多出现一次,序列中相邻的城市之间由公路直接相连(待改建为铁路)。并且,每个城市最多只能出现在一条规划路线中,也就是说,任意两条规划路线不能有公共部分。 当然在一般情况下是不可能将所有的公路修建为铁路的,因此从有些城市出发去往首都依然需要通过乘坐长途汽车,而长途汽车只往返于公路连接的相邻的城市之间,因此从某个城市出发可能需要不断地换乘长途汽车和火车才能到达首都。 我们定义一个城市的“不便利值”为从它出发到首都需要乘坐的长途汽车的次数,而Z 国的交通系统的“不便利值”为所有城市的不便利值的最大值,很明显首都的“不便利值”为0。小Z 想知道如何确定规划路线修建铁路使得Z 国的交通系统的“不便利值”最小,以及有多少种不同的规划路线的选择方案使得“不便利值”达到最小。当然方案总数可能非常大,小Z 只关心这个天文数字mod Q 后的值。 注意:规划路线1-2-3 和规划路线3-2-1 是等价的,即将一条规划路线翻转依然认为是等价的。两个方案不同当且仅当其中一个方案中存在一条规划路线不属于另一个方案。
Input

第一行包含三个正整数N、M、Q,其中N 表示城市个数,M 表示公路总数,N 个城市从1~N 编号,其中编号为1 的是首都。Q 表示上文提到的设计路线的方法总数的模数。接下来M 行,每行两个不同的正数ai、bi (1≤ ai , bi ≤ N)表示有一条公路连接城市ai 和城市bi。 输入数据保证一条公路只出现一次。
Output

包含两行。第一行为一个整数,表示最小的“不便利值”。 第二行为一个整数,表示使“不便利值”达到最小时不同的设计路线的方法总数 mod Q 的值。如果某个城市无法到达首都,则输出两行-1。
Sample Input
5 4 100
1 2
4 5
1 3
4 1
Sample Output
1
10
HINT

以下样例中是10 种设计路线的方法: (1) 4-5 (2) 1-4-5 (3) 4-5, 1-2 (4) 4-5, 1-3 (5) 4-5, 2-1-3 (6) 2-1-4-5 (7) 3-1-4-5 (8) 1-4 (9) 2-1-4 (10) 3-1-4 【数据规模和约定】对于20%的数据,满足N,M ≤ 10。对于50%的数据,满足N,M ≤ 200。对于60%的数据,满足N,M ≤ 5000。对于100%的数据,满足1 ≤ N,M ≤ 100000,1 ≤ Q ≤ 120000000。

 

树dp(首先判断是否连通),因为最后的方案不一定要所有的都选最优方案,所以dp[i][j][k]表示以节点i为根,不便利值不大于j,节点i向儿子连了k条边的方案数(k=0,1,2)

我们很轻易的想到了下面这个方程(借将狼踩尽的图)

关键是这个肯定超时,所以要优化(每搜索一个儿子做一遍,初始f[i,j,0]=1)

我是这样理解的,其实相当于每次加上一个儿子,然后更新f的值(这样应该很清楚吧)

 1 const
 2         maxn=100010;
 3 var
 4         f:array[0..maxn,-1..10,0..2]of int64;
 5         first,next,last:array[0..maxn*2]of longint;
 6         flag:array[0..maxn]of boolean;
 7         n,m,tot:longint;
 8         q:int64;
 9  
10 procedure insert(x,y:longint);
11 begin
12         inc(tot);
13         last[tot]:=y;
14         next[tot]:=first[x];
15         first[x]:=tot;
16 end;
17  
18 procedure init;
19 var
20         i,x,y:longint;
21 begin
22         read(n,m,q);
23         if m<>n-1 then
24         begin
25           writeln(-1);
26           writeln(-1);
27           halt;
28         end;
29         for i:=1 to m do
30           begin
31             read(x,y);
32             insert(x,y);
33             insert(y,x);
34           end;
35 end;
36  
37 function get(x:int64):int64;
38 begin
39         if (x>0) and (x mod q=0) then exit(q);
40         exit(x mod q);
41 end;
42  
43 procedure dfs(x:longint);
44 var
45         i,j:longint;
46         f1,f2:int64;
47 begin
48         j:=first[x];
49         flag[x]:=true;
50         for i:=0 to 10 do
51           f[x,i,0]:=1;
52         while j<>0 do
53           begin
54             if flag[last[j]]=false then
55             begin
56               dfs(last[j]);
57               for i:=0 to 10 do
58                 begin
59                   f1:=f[last[j],i,0]+f[last[j],i,1];
60                   f2:=f[last[j],i-1,0]+f[last[j],i-1,1]+f[last[j],i-1,2];
61                   f[x,i,2]:=get(f[x,i,2]*f2+f[x,i,1]*f1);
62                   f[x,i,1]:=get(f[x,i,1]*f2+f[x,i,0]*f1);
63                   f[x,i,0]:=get(f[x,i,0]*f2);
64                 end;
65             end;
66             j:=next[j];
67           end;
68 end;
69  
70 procedure work;
71 var
72         i:longint;
73 begin
74         dfs(1);
75         for i:=0 to 10 do
76           if f[1,i,0]+f[1,i,1]+f[1,i,2]>0 then
77           begin
78             writeln(i);
79             writeln((f[1,i,0]+f[1,i,1]+f[1,i,2])mod q);
80             exit;
81           end;
82         writeln(-1);
83         writeln(-1);
84 end;
85  
86 begin
87         init;
88         work;
89 end.
View Code

 

转载于:https://www.cnblogs.com/Randolph87/p/3679223.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值