2018.8.12T2

描述
可怜最近在玩一款非常有意思的游戏:在游戏中她扮演了一支起义军的首领并在乱世中统一了天下。

现在可怜要给她手下的 K 个功臣分配封地。她选定了 n(n>K)个城市,这 n 个城市被 n−1条双向道路联通,每一条道路的长度都是 1。两个城市i,j 的交通便捷度为 i 到 j 的最短路径长度。

现在可怜要给每一个城市选定一个功臣担任城主。可能有多个城主由同一个人担任,也有可能一个人没有担任任何城主:这些都不是可怜关心的。可怜关心的是,如何巩固她自己的统治:一个功臣统治的城池距离越近,那么他个人的军事力量就会越强大,也越容易威胁到可怜。

定义一个功臣的力量值 wi w i 为他统治的城池两两间交通便捷度的最小值,如果他统治的城池不足 2 个,那么 wi=109 w i = 10 9 。可怜想要分配城主使得 min(wi) m i n ( w i ) 最大,现在她想要知道这个最大值是多少,以及能够达到这个最大值的分配方案有多少个。

输入格式
第一行两个整数 n,K 表示城池数与功臣数。

接下来 n−1 行每行两个数 u,v(1≤u≠v≤n) 表示一条道路。

输出格式
输出一行两个整数表示 min(wi) m i n ( w i ) 的最大值以及能达到这个最大值的方案数。方案数可能很大,对 998244353 取模后输出。

样例1
样例输入1
4 2
1 2
2 3
2 4
样例输出1
2 2
样例2
样例输入2
5 3
1 2
1 3
1 4
1 5
样例输出2
2 48
限制与约定
对于 10% 的数据,保证 n≤8
对于 30% 的数据,保证 n≤50
对于 60%的数据,保证 n≤500
对于另外 20% 的数据,保证第 i 条边连接着 i,i+1。
对于 100% 的数据,保证 1≤K < < <script type="math/tex" id="MathJax-Element-762"><</script>n≤2000
时间限制:2s

空间限制:512MB


我们可以发现链的数据比较好做,对于某个点,相当于是限制了一段区间不能有颜色有相同。

这个可以对我们所有数据下的第一问有点启发
我们考虑一个 ans1 a n s 1 合法的充要条件

不难发现对于一个合法的 ans1 a n s 1
需要满足任取一个点,所有距离这个点小于 ans12 a n s 1 2 的点数不得超过 k k
这里我们取的点只有端点和某一条边的中点
因为一条路径的中点只可能落在端点以及边的中点上
我们暂且称端点+中点为关键点

二分的复杂度是不能接受的
但是我们不难发现上面那个判定问题我们可以直接bfs求出每一个关键点满足条件的最大的 wi w i
我们只要把距离 i i k个近的端点和第 k+1 k + 1 拉出来讨论即可

第二问就比较好处理了
一个 dfs d f s 就可以解决,对于每个关键点我们把距离他小于 ans1 a n s 1 的端点染色
对于两个相邻的关键点,他们有重复部分和独立部分
对于当前染到的点 i i ,我们可以记重复部分有sum1个,独立部分有 sum2 s u m 2
那么这里就有 Csum2ksum1sum2! C k − s u m 1 s u m 2 ∗ s u m 2 ! 种不同的方案
根据乘法原理我们只要把每个点的上式乘起来即可

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define ll long long
const int p = 998244353;
int linkk[4010] , t , n , k;
bool flag[4010];
ll C[2010][2010] , jc[4010];
int ans1 = 2000000000;
ll ans2;
struct node{
    int n , y;
}e[8010];

namespace fastIO{ 
    #define BUF_SIZE 100000 
    #define OUT_SIZE 100000 
    bool IOerror=0; 
    inline char nc(){ 
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE; 
        if (p1==pend){ 
            p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin); 
            if (pend==p1){IOerror=1;return -1;} 
        } 
        return *p1++; 
    } 
    inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';} 
    inline void read(int &x){ 
        bool sign=0; char ch=nc(); x=0; 
        for (;blank(ch);ch=nc()); 
        if (IOerror)return; 
        if (ch=='-')sign=1,ch=nc(); 
        for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0'; 
        if (sign)x=-x; 
    } 
    inline void read(ll &x){ 
        bool sign=0; char ch=nc(); x=0; 
        for (;blank(ch);ch=nc()); 
        if (IOerror)return; 
        if (ch=='-')sign=1,ch=nc(); 
        for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0'; 
        if (sign)x=-x; 
    } 
    #undef OUT_SIZE 
    #undef BUF_SIZE 
}; 
using namespace fastIO;

void insert(int x,int y)
{
    e[++t].y = y;e[t].n = linkk[x];linkk[x] = t;
    e[++t].y = x;e[t].n = linkk[y];linkk[y] = t;
    return;
}
void init()
{
    read(n);read(k);
    rep(i,1,n-1)
    {
        int x , y;
        read(x);read(y);
        insert(x , i + n);
        insert(i + n , y);
    }
    C[0][0] = 1;
    rep(i,1,n)
    {
        C[i][0] = C[i][i] = 1;
        rep(j,1,i-1) C[i][j] = (C[i-1][j] + C[i-1][j-1])%p;
    }
    jc[0] = 1;
    rep(i,1,2*n) jc[i] = i * jc[i-1] % p;
    return;
}
queue<int>q;
int dep[4010] , tmp[4010] , o;
bool vis[4010];
void bfs(int x)
{
    o = 0;
    memset(vis,0,sizeof(vis));
    dep[x] = 0;vis[x] = true;q.push(x);
    while(!q.empty())
    {
        int u = q.front();if(u <= n)tmp[++o] = u;
        for(int i = linkk[u];i;i = e[i].n)
            if(!vis[e[i].y])
            {
                vis[e[i].y] = true;
                dep[e[i].y] = dep[u] + 1;
                q.push(e[i].y);
            }
        q.pop();
    }
    return;
}
void dfs(int x,int fa)
{
    bfs(x);
    int sum1 = 0, sum2 = 0;//sum1为重合部分,sum2为单独部分
    for(int i = 1;dep[tmp[i]] < ans1 && i <= o;++i)
        if(flag[tmp[i]]) sum1++;
        else sum2++ , flag[tmp[i]] = true;
    ans2 = (ans2 * C[k-sum1][sum2] % p) * jc[sum2] %p;
    rept(i,x) if(e[i].y != fa) dfs(e[i].y , x);
    return;
}
int main()
{
    init();
    bfs(1);
    rep(i,1,2*n) bfs(i),ans1 = min(ans1 , dep[tmp[k]] == dep[tmp[k+1]]? dep[tmp[k]] : dep[tmp[k]]+1);
    ans2 = 1;
    dfs(1,0);
    printf("%d %lld\n",ans1,ans2);
    return 0;
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值