• iai 定向 题解


    题目

    题意

    给定一棵树,给 n − 1 n-1 n1 条边定向,求恰有 k k k 个点无出边的方案数。

    解析

    设计 f ( u , i , 0 / 1 ) f(u,i,0/1) f(u,i,0/1) 表示以 u u u 为根的子树内,有 i i i 个无出边, u u u 是否有出边的方案数。

    树背包。

    考虑转移。对 v ∈ s o n u v \in son_u vsonu,枚举 j j j,钦定 v v v 子树贡献为 j j j,则 v v v 之前贡献为 i − j i-j ij,讨论边的方向:

    u → v u \to v uv

    f ( u , i , 1 ) = ∑ j ( f ( u , i − j + 1 , 0 ) + f ( u , i − j , 1 ) ) × ( f ( v , j , 0 ) + f ( v , j , 1 ) ) f(u,i,1) = \sum_{j} (f(u,i-j+1,0) +f(u,i-j,1)) \times (f(v,j,0)+f(v,j,1)) f(u,i,1)=j(f(u,ij+1,0)+f(u,ij,1))×(f(v,j,0)+f(v,j,1))

    v → u v \to u vu

    f ( u , i , 1 ) = ∑ j f ( u , i − j , 1 ) × ( f ( v , j + 1 , 0 ) + f ( v , j , 1 ) ) f ( u , i , 0 ) = ∑ j f ( u , i − j , 0 ) × ( f ( v , j + 1 , 0 ) + f ( v , j , 1 ) ) f(u,i,1) = \sum_j f(u,i-j,1) \times (f(v,j+1,0)+f(v,j,1))\\ f(u,i,0) = \sum_j f(u,i-j,0) \times (f(v,j+1,0)+f(v,j,1)) f(u,i,1)=jf(u,ij,1)×(f(v,j+1,0)+f(v,j,1))f(u,i,0)=jf(u,ij,0)×(f(v,j+1,0)+f(v,j,1))

    注意树背包滚动数组的特点,倒序枚举,每轮的 f f f 值不要继承。

    #include
    #define int long long
    using namespace std;
    
    const int N = 1005;
    const int mod = 998244353;
    
    vector <int> G[N];
    
    int n, t, siz[N], f[N][N][2];
    
    void dfs(int u, int fa)
    {
    	f[u][1][0] = 1, siz[u] = 1;
    	for(auto v : G[u])
    	{
    		if(v == fa) continue;
    		dfs(v, u), siz[u] += siz[v];
    		for(int i=min(t, siz[u]); i>=1; i--)
    		{
    			int cur0 = 0, cur1 = 0;
    			for(int j=0; j<=min(i, siz[v]); j++)
    			{
    				cur1 += (f[u][i-j][1] + f[u][i-j+1][0]) * (f[v][j][0] + f[v][j][1]) % mod, cur1 %= mod;
    				cur1 += f[u][i-j][1] * (f[v][j+1][0] + f[v][j][1]) % mod, cur1 %= mod;
    				cur0 += f[u][i-j][0] * (f[v][j+1][0] + f[v][j][1]) % mod, cur0 %= mod;
    			}
    			f[u][i][0] = cur0, f[u][i][1] = cur1;
    		}
    	}
    }
    
    signed main()
    {
    	ios::sync_with_stdio(0); cin.tie(0);
    	
    	cin >> n;
    	
    	for(int i=1; i<n; i++)
    	{
    		int u, v;
    		cin >> u >> v;
    		G[u].push_back(v), G[v].push_back(u);
    	}
    	
    	cin >> t;
    	
    	dfs(1, 0);
    	
    	cout << (f[1][t][0] + f[1][t][1]) % mod;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
  • 相关阅读:
    面向对象编程原则(05)——里氏替换原则
    取代 Mybatis Generator,这款代码生成神器配置更简单,开发效率更高!
    线程三连鞭之“线程基础”
    使用公式在Excel中指定列值的变化实现自动间隔着色(不是按照固定的行数)
    Golang设计模式
    STM32CubeMX和Keil uVision5软件
    学习笔记—吴恩达《AI for everyone》
    双十一购买什么最划算,最值得入手的几款数码好物推荐
    @Elasticsearch之深度应用及原理剖析--文档搜索机制剖析
    anaconda、python卸载后重装以及anaconda--443
  • 原文地址:https://blog.csdn.net/weixin_73113801/article/details/134044726