• 【LG3687】[ZJOI2017]仙人掌


    题面

    洛谷

    题解

    实际上是各个环之间的森林上的链不重复覆盖边的问题。

    原问题是不能覆盖重边的,但是我们这里假设可以覆盖重边,一条边不覆盖就等价于覆盖一条重边,

    那么问题转化为覆盖树上所有边有多少种方法。

    注意到树上某个点的方案数与其他点无关,而只与自己的度数有关,也就是说一个点的所有边进行不同的匹配都对应了一种不同的覆盖方案。

    那么设(f_i)表示度数为(i)的点相邻的边的匹配方案数,那么有(f_i=f_{i-1}+(i-1) imes f_{i-2})

    边界条件(f_0=f_1=1)

    那么答案就是(prod_{iin ext{森林}} f_i)

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring> 
    #include <cmath> 
    #include <algorithm>
    using namespace std; 
    inline int gi() {
        register int data = 0, w = 1;
        register char ch = 0;
        while (!isdigit(ch) && ch != '-') ch = getchar(); 
        if (ch == '-') w = -1, ch = getchar(); 
        while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar(); 
        return w * data; 
    } 
    const int Mod = 998244353; 
    const int MAX_N = 5e5 + 5; 
    struct Graph { int to, next; } e[MAX_N << 2]; 
    int fir[MAX_N], e_cnt; 
    void Add_Edge(int u, int v) { e[e_cnt] = (Graph){v, fir[u]}, fir[u] = e_cnt++; } 
    int N, M, f[MAX_N], deg[MAX_N]; 
    int vis[MAX_N], dfn[MAX_N], fa[MAX_N], tim;
    bool flag = 0; 
    void dfs(int x) { 
    	dfn[x] = ++tim; 
    	for (int i = fir[x]; ~i; i = e[i].next) { 
    		int v = e[i].to; 
    		if (v == fa[x]) continue; 
    		if (!dfn[v]) fa[v] = x, dfs(v); 
    		else if (dfn[v] > dfn[x]) { 
    			deg[x] -= 2; 
    			for (int u = v; u != x; u = fa[u]) { 
    				if (vis[u]) return (void)(flag = 1); 
    				vis[u] = 1, deg[u] -= 2; 
    			} 
    		} 
    		if (flag) return ; 
    	} 
    } 
    int main () { 
    #ifndef ONLINE_JUDGE 
        freopen("cpp.in", "r", stdin); 
    #endif 
    	memset(fir, -1, sizeof(fir)); 
    	f[0] = f[1] = 1; 
    	for (int i = 2; i <= 5e5; i++) f[i] = (f[i - 1] + 1ll * (i - 1) * f[i - 2]) % Mod; 
    	int Q = gi(); 
    	while (Q--) { 
    		N = gi(), M = gi(); 
    		for (int i = 1; i <= M; i++) { 
    			int u = gi(), v = gi(); 
    			Add_Edge(u, v), Add_Edge(v, u); 
    			deg[u]++, deg[v]++; 
    		} 
    		dfs(1); 
    		if (flag) puts("0"); 
    		else {
    			int ans = 1;
    			for (int i = 1; i <= N; i++) ans = 1ll * ans * f[deg[i]] % Mod; 
    			printf("%d
    ", ans); 
    		} 
    		for (int i = 1; i <= N; i++) vis[i] = dfn[i] = deg[i] = 0, fir[i] = -1; 
    		flag = 0, e_cnt = 0; 
    	} 
        return 0; 
    } 
    
  • 相关阅读:
    FCKEditor装入模板方法
    医道再解开阖枢
    测试一下 Last
    [技术架构] 大型互联网站解决高并发的常见策略
    swfupload实现图片及缩略图上传
    解决“在证书存储区中找不到清单签名证书”
    asp.net EnableViewState禁用与注意事项
    jQuery创建水平和垂直居中的div窗口
    甩掉ashx/asmx,使用jQuery.ajaxWebService请求WebMethod,Ajax处理更加简练
    type="button" ,"submit" 的区别(转)
  • 原文地址:https://www.cnblogs.com/heyujun/p/12198657.html
Copyright © 2020-2023  润新知