zoukankan      html  css  js  c++  java
  • [JSOI2018]潜入行动

    首先定义一个比较显然的状态:(f[i][j][4]),其中

    (f[i][j][0])表示以(i)为根的子树安装了(k)个监视器,且节点(i)安装了监视器并被监听;

    那么,相同地

    (f[i][j][1])表示节点(i)安装了监视器且不被监听

    (f[i][j][2])表示节点(i)未安装监视器且被监听

    (f[i][j][3])表示节点(i)未安装监视器且不被监听

    注意,上述状态内的是否被监听均指是否被自己的儿子节点监听。

    然后,我们按照常规的树形背包转移套路对状态进行转移,于是我们就有了如下转移方程:

    [f[u][i][3] = sum f[v][j][2] * f[u][i-j][3] ]

    [f[u][i][2] = sum (f[v][j][0]+f[v][j][2]) * (f[u][i-j][2]+f[u][i-j][3]) ]

    [f[u][i][1] = sum (f[v][j][2]+f[v][j][3]) * f[u][i-j][1] ]

    [f[u][j][0] = sum (f[v][j][0]+f[v][j][1]+f[v][j][2]+f[v][j][3]) * (f[u][i-j][0]+f[u][i-j][1]) ]

    然后,我们发现在转移(0)(2)两个状态的时候,因为我们无法枚举每个子节点是否有安装的或都不安装,但我们可以知道如果当前节点没有被监听,子节点肯定都没有安装,所以我们可以利用这个把多余的状态去掉:

    [f[u][i][0] -= f[u][i][1] f[u][i][2] -= f[u][i][3] ]

    还有一点需要注意,因为我们是在做树上的计数类(DP)问题,所以在考虑当前节点的一个子节点时,剩下子节点的状态不能保留,要临时记录下来,防止转移时混乱或出现各种玄学错误。

    然后就是复杂度的分析:

    略微思考一下你会发现,在进行上述(DP)转移的时候,我们的时间复杂度疑似是(O(nk^2)),但只要我们枚举转移的时候边界控制的足够优美,它的时间复杂度会进一大步下降到(O(nk)),所以在本题(k leq 100)的情况下,完全是可过的。

    其实对于边界的控制也很简单,我们只需注意枚举(i)的时候不能超出当前子树的大小,枚举(j)的时候要注意(i-j)不能大于(siz[u]-siz[v])且也要小于子树大小。

    code:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define min(a, b) ((a) < (b) ? (a) : (b))
    #define max(a, b) ((a) > (b) ? (a) : (b))
    #define rint register int
    #define LL long long
     
    const int maxn = 1e5 + 5;
    const int MOD = 1e9 + 7;
    int n, k, tot, head[maxn], f[maxn][105][4], siz[maxn], g[105][4];
    
    /*
    0 -> 安装且被监听
    1 -> 安装且不被监听
    2 -> 不安装被监听
    3 -> 不安装不被监听
    */
    
    struct Edge {
    	int to, nxt;
    	Edge(int _to, int _nxt) {
    		this -> to = _to;
    		this -> nxt = _nxt;
    	} Edge(){}
    }edge[maxn << 1];
    
    void add(int from, int to) {edge[++tot] = Edge(to, head[from]), head[from] = tot;}
    
    template<class T>
    inline T read(T &x) {
    	x = 0; int w = 1, ch = getchar();
    	for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') w = -1;
    	for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - 48;
    	return x *= w;
    } 
    
    void dfs(int u, int fa) {
    	f[u][1][1] = 1; f[u][0][3] = 1; siz[u] = 1;
    	for (rint i = head[u]; i; i = edge[i].nxt) {
    		int v = edge[i].to; 
    		if (v == fa) continue;
    		dfs(v, u);
    		siz[u] += siz[v]; memcpy(g, f[u], sizeof(g));
    		for (rint j = min(siz[u], k); ~j; j--) f[u][j][0] = f[u][j][1] = f[u][j][2] = f[u][j][3] = 0;
    		for (rint j = min(siz[u], k); ~j; j--) {
    			for (rint p = max(0, j + siz[v] - siz[u]); p <= min(siz[v], j); p++) {
    				f[u][j][3] += ((LL)f[v][p][2] * g[j - p][3]) % MOD, f[u][j][3] %= MOD;
    				f[u][j][2] += ((LL)(f[v][p][0] % MOD + f[v][p][2] % MOD) % MOD) *
    							  ((g[j - p][2] % MOD + g[j - p][3] % MOD) % MOD) % MOD; 
    				f[u][j][2] %= MOD;
    				f[u][j][1] += ((LL)(f[v][p][2] % MOD + f[v][p][3] % MOD)) % MOD * 
    							  g[j - p][1] % MOD; f[u][j][1] %= MOD;
    				f[u][j][0] += ((LL)(f[v][p][0] + f[v][p][1] % MOD) + (f[v][p][2] + f[v][p][3]) % MOD)
    				 			  % MOD * ((g[j - p][1] % MOD+ g[j - p][0] % MOD)) % MOD; f[u][j][0] %= MOD;
    			}
    			f[u][j][0] = (f[u][j][0] - f[u][j][1] + MOD) % MOD; 
    			f[u][j][2] = (f[u][j][2] - f[u][j][3] + MOD) % MOD; 	
    		}
    	}
    }
    
    int main() {
    	int x, y;
    	read(n), read(k);
    	for (int i = 1; i < n; i++) {
    		read(x), read(y);
    		add(x, y), add(y, x);
    	}
    	dfs(1, 0);
    	std::cout << f[1][k][0] + f[1][k][2]<< '
    ';
    	return 0;
    }
    

    后话

    我和@Flandre_495一同做此题的过程:

    我:又是计数类(DP)……

    F:你感觉复杂度多少?

    我:三维状态,然后树形背包平凡,大概(O(nk))吧。

    随手向下一翻,嗯!?(k leq min(n,100))!!

    我们俩同时握住对方的手:水黑题,切了他!

    (………………One and a half hours later)

    我和@Flandre_495对视一眼:确认过眼神,这是道黑题……

    完结撒花♪(・ω・)ノ

  • 相关阅读:
    打造自己的 C# WinForm 应用程序的 SQL Server 连接配置界面
    怎么修改app.config的值
    将DATATABLE中的数据导入到数据库中
    C# 多线程使用progressBar进度条控件
    程序员技术练级攻略2
    c#中Setting.setting的使用
    该行已经属于另一个表
    Microsoft 数据访问技术的过去、现在和未来
    Winform专栏
    在 C# 中使用设置 Settings.settings
  • 原文地址:https://www.cnblogs.com/Hydrogen-Helium/p/11817934.html
Copyright © 2011-2022 走看看