[bzoj1063][NOI2008]道路設計
1063: [Noi2008]道路設計
Time Limit: 20 Sec Memory Limit: 162 MB
Submit: 931 Solved: 509
[Submit][Status][Discuss]
Description
Z國坐落於遙遠而又神奇的東方半島上,在小Z的統治時代公路成為這裡主要的交通手段。Z國共有n座城市,一
些城市之間由雙向的公路所連線。非常神奇的是Z國的每個城市所處的經度都不相同,並且最多隻和一個位於它東
邊的城市直接通過公路相連。Z國的首都是Z國政治經濟文化旅遊的中心,每天都有成千上萬的人從Z國的其他城市
湧向首都。為了使Z國的交通更加便利順暢,小Z決定在Z國的公路系統中確定若干條規劃路線,將其中的公路全部
改建為鐵路。我們定義每條規劃路線為一個長度大於1的城市序列,每個城市在該序列中最多出現一次,序列中相
鄰的城市之間由公路直接相連(待改建為鐵路)。並且,每個城市最多隻能出現在一條規劃路線中,也就是說,任意
兩條規劃路線不能有公共部分。當然在一般情況下是不可能將所有的公路修建為鐵路的,因此從有些城市出發去往
首都依然需要通過乘坐長途汽車,而長途汽車只往返於公路連線的相鄰的城市之間,因此從某個城市出發可能需要
不斷地換乘長途汽車和火車才能到達首都。我們定義一個城市的“不便利值”為從它出發到首都需要乘坐的長途汽
車的次數,而Z國的交通系統的“不便利值”為所有城市的不便利值的最大值,很明顯首都的“不便利值”為0。小
Z想知道如何確定規劃路線修建鐵路使得Z國的交通系統的“不便利值”最小,以及有多少種不同的規劃路線的選擇
方案使得“不便利值”達到最小。當然方案總數可能非常大,小Z只關心這個天文數字modQ後的值。注意:規劃路
線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
包含兩行。第一行為一個整數,表示最小的“不便利值”。第二行為一個整數,表示使“不便利值”達到最小時
不同的設計路線的方法總數modQ的值。如果某個城市無法到達首都,則輸出兩行-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
【資料規模和約定】
對於100%的資料,滿足1≤N,M≤100000,1≤Q≤120000000。
最多隻和一個位於它東邊的城市相連,說明這是一個樹。
那答案的最大值不會超過樹的深度。但其實這個最大值會很小。
因為每次減小的時候我們肯定都是要找一個長的鏈減小,然後從剩下的短的鏈裡也繼續這樣做。這個過程其實就相當於在樹鏈剖分,我們知道樹鏈剖分的上界是
這樣的話設
做到每一個兒子的時候更新一下當前的根的答案就行了。
複雜度:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define LL long long
const int N=100010;
LL f[N][20][3];
struct S{int st,en;}aa[N<<1];
int n,m,Mod,tot,point[N],next[N<<1];
inline int in(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void add(int x,int y){
next[++tot]=point[x];point[x]=tot;
aa[tot].st=x;aa[tot].en=y;
next[++tot]=point[y];point[y]=tot;
aa[tot].st=y;aa[tot].en=x;
}
inline LL calc(LL x){
if(x&&x%Mod==0) return Mod;
else return x%Mod;
}
inline void dp(int x,int last){
int i,j;
for(i=0;i<20;++i) f[x][i][0]=1;
for(i=point[x];i;i=next[i])
if(aa[i].en!=last){
dp(aa[i].en,x);
for(j=0;j<20;++j){
LL o0=calc(f[aa[i].en][j][0]+f[aa[i].en][j][1]);
LL o1=(j?(calc(f[aa[i].en][j-1][0]+f[aa[i].en][j-1][1]+f[aa[i].en][j-1][2])):0);
f[x][j][2]=calc(f[x][j][1]*o0+f[x][j][2]*o1);
f[x][j][1]=calc(f[x][j][0]*o0+f[x][j][1]*o1);
f[x][j][0]=calc(f[x][j][0]*o1);
}
}
}
int main(){
int i,x,y;
n=in();m=in();Mod=in();
if(m<n-1){
printf("-1\n-1\n");
return 0;
}
for(i=1;i<=m;++i){
x=in();y=in();
add(x,y);
}
dp(1,0);
for(i=0;i<20;++i)
if(f[1][i][0]+f[1][i][1]+f[1][i][2]>0){
printf("%d\n%d\n",i,(int)(f[1][i][0]+f[1][i][1]+f[1][i][2])%Mod);
return 0;
}
printf("-1\n-1\n");
}