首页 > 其他 > 详细

题解P4201: [NOI2008]设计路线

时间:2019-12-29 23:43:41      阅读:71      评论:0      收藏:0      [点我收藏+]

发现给出了一棵树, 不是树的情况直接输出-1

考虑进行DP, 设f[i][0/1/2]为i的子树中选小于等于0/1/2条边修路的方案数, 不妨对于一个节点, 先考虑正好相等的情况, 假设当前扫到了一个节点v, 则有

\[ f[i][0] = \max\{f[i][0]\, f[v][2]+1\} \f[i][1] = \min\{\max\{f[i][1], f[v][2]+1\}, \max\{f[i][0], f[v][1]\}\} \f[i][2] = \min\{\max\{f[i][2], f[v][2]+1\}, \max\{f[i][1], f[v][1]\}\} \]

接下来前缀min一下即可, 注意到要2->1->0更新, 并且要前缀min

接下来考虑DP出方案数, 发现我们所求的f[1][2]的最大值是\(O(log_3 n) \leq 11\)的, 因此设计状态时要把这个作为一个维度

咕咕咕

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define _ 100005
#define rep for(int t=0; t<=f[1][2]; ++t)
int f[_][3], g[_][20][3], inf=0x3f3f3f3f;
int Next[_<<1], ver[_<<1], head[_], tot;
int n, m, q;
int gv(int x, int y, int z){
    if(x>=0 && y>=0 && z>=0) return g[x][y][z]; return 0;
}
void dfs1(int u, int fa){
    f[u][0] = 0, f[u][1] = inf, f[u][2] = inf;
    for(int i=head[u]; i; i=Next[i]){
        int v=ver[i]; if(v == fa) continue; dfs1(v, u);
        f[u][2] = min(max(f[u][2], f[v][2]+1), max(f[u][1], f[v][1]));
        f[u][1] = min(max(f[u][1], f[v][2]+1), max(f[u][0], f[v][1]));
        f[u][0] = max(f[u][0], f[v][2]+1);
    }
    f[u][1] = min(f[u][0], f[u][1]); f[u][2] = min(f[u][2], f[u][1]);
}
void dfs2(int u, int fa){
    rep g[u][t][0]=1, g[u][t][1]=g[u][t][2]=0;
    for(int i=head[u]; i; i=Next[i]){
        int v=ver[i]; if(v == fa) continue; dfs2(v, u);
        rep {
            g[u][t][2] = gv(u, t ,2)*gv(v, t-1, 2) + gv(u, t, 1)*gv(v, t, 1); g[u][t][2]%=q;
            g[u][t][1] = gv(u, t, 1)*gv(v, t-1, 2) + gv(u, t, 0)*gv(v, t, 1); g[u][t][1]%=q;
            g[u][t][0] = gv(u, t, 0)*gv(v, t-1, 2); g[u][t][0]%=q;
        }
    }
    rep (g[u][t][1]+=g[u][t][0])%=q, (g[u][t][2]+=g[u][t][1])%=q;
}
void add(int u, int v){
    ver[++tot]=v, Next[tot]=head[u], head[u]=tot;
}
signed main(){
    scanf("%lld%lld%lld", &n, &m, &q);
    if(m != n-1) return (puts("-1"), puts("-1"), 0);
    for(int i=1; i<=m; ++i){
        int x, y; scanf("%lld%lld", &x, &y); add(x, y); add(y, x);
    }
    dfs1(1, 0); dfs2(1, 0);
    printf("%lld\n%lld\n", f[1][2], gv(1, f[1][2], 2));
}

题解P4201: [NOI2008]设计路线

原文:https://www.cnblogs.com/tyqtyq/p/12116967.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!