[bzoj1063][Noi2008]道路设计

来自FallDream的博客,未经允许,请勿转载,谢谢。


 

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

n<=100000 Q<=120000000

 

第一问是树形dp,f[i][0/1/2]表示第i个点,向下建了0/1/2条道路的最长的长度的最小值。

可以用树剖证明答案是log级的。

这样就直接计算方案数就行了 g[i][0/1/2][k]表示第i个点向下建了0/1/2条道路,最长的路的长度是k的方案数

复杂度nlog^2n

#include<iostream>
#include<cstdio>
#define MN 100000
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
int n,m,mod,head[MN+5],cnt=0,g[MN+5],G[MN+5],f[3][65][MN+5],F[3][65][MN+5];
struct edge{int to,next;}e[MN*2+5];
inline void ins(int f,int t)
{
    e[++cnt]=(edge){t,head[f]};head[f]=cnt;
    e[++cnt]=(edge){f,head[t]};head[t]=cnt;
}

void Pre(int x,int fa)
{
    g[x]=G[x]=0;int mx=0;
    for(int i=head[x];i;i=e[i].next)
        if(e[i].to!=fa)
        {
            Pre(e[i].to,x);
            G[x]=min(max(G[x],G[e[i].to]+1),max(g[x],g[e[i].to]));
            g[x]=min(max(mx,g[e[i].to]),max(g[x],G[e[i].to]+1));
            mx=max(mx,G[e[i].to]+1);    
        }
    G[x]=min(G[x],g[x]);
}
inline void R(int&x,int y){x+=y;x>=mod?x-=mod:0;}
void Dp(int x,int fa)
{
    f[0][0][x]=1%mod;    
    for(int i=head[x];i;i=e[i].next)
        if(e[i].to!=fa)
        {
            Dp(e[i].to,x);
            for(int j=2;~j;--j)
                for(int k=m;~k;--k)
                    for(int l=m;~l;--l)
                    {
                        if(j<2) R(F[j+1][max(l,k)][x],1LL*f[j][l][x]*(f[0][k][e[i].to]+f[1][k][e[i].to])%mod);
                        R(F[j][max(l,k+1)][x],1LL*f[j][l][x]*(f[0][k][e[i].to]+f[1][k][e[i].to]+f[2][k][e[i].to])%mod);
                    }
            for(int j=0;j<=2;++j)
                for(int k=0;k<=m;++k)
                    f[j][k][x]=F[j][k][x],F[j][k][x]=0;
        }
}

int main()
{
    n=read();m=read();mod=read();
    if(m<n-1) return 0*puts("-1\n-1");
    for(int i=1;i<n;++i) ins(read(),read());
    Pre(1,0);m=G[1];
    Dp(1,0);
    printf("%d\n%d\n",m,(f[0][m][1]+f[1][m][1]+f[2][m][1])%mod);
    return 0;
}
posted @ 2017-07-02 09:18  FallDream  阅读(275)  评论(0编辑  收藏  举报