zoukankan      html  css  js  c++  java
  • 【gdoi2018 day2】第二题 滑稽子图(subgraph)(性质DP+多项式)

    题目大意 【gdoi2018 day2】第二题 滑稽子图(subgraph)
    • 给你一颗树(T),以及一个常数(K),对于(T)的点集(V)的子集(S).

    • 定义(f(S))为点集(S)的导出子图的边数(一条原树中的边只有两个端点都出现在(S)中,才会出现在导出子图中)

    数据范围

    这里写图片描述

    解题方案
    (Part_1) 5%
    • 随便做
    (Part_2) 30%
    • 考虑一下DP.

    • (f[i][j][0/1])表示第(i)个点,导出子图边数为(j),第(i)个点是否选.

    • 转移讨论一下即可,这里需要注意一下转移时用顺推还是逆推.

    • 一般来说,对于背包类型的,我们顺推可以使每一个转移都是有效的.

    • 枚举之前子树大小和,以及当前子树大小,乘积的和是(O(n^2))级别的.

    • 证明:

      • 两个点会产生贡献,当且仅当它们的(LCA)为当前的根时,每两个点的(LCA)唯一,故只有(O(n^2))个点会产生贡献.
    (Part_3) 100% DP
    • 依然是DP,但我们要利用好(kle 10)这个特性.

    • 我们来观察一下顺推时的转移,其实可以表示为:

      • 令当前计算的是(y)对于父亲(x)的贡献,表达如下:

      [f[x][i + j] = sum_{i = 0}^{size_x - 1}sum_{j=0}^{size_y-1} f[x][i] * f[y][j] * (i + j) ^ k ]

    (qquad qquad qquad qquad qquad qquad qquad qquad qquad Downarrow)
    $$f[x][i + j] = sum_{i = 0}^{size_x - 1}sum_{j = 0}^{size_y - 1} f[x][i]f[y][j] * sum_{t = 0}kitj^{k-t}inom{k}{t}$$
    (qquad qquad qquad qquad qquad qquad qquad qquad qquad Downarrow)
    $$f[x][i + j] = sum_{i = 0}^{size_x - 1}sum_{j = 0}^{size_y - 1} sum_{t = 0}^kinom{k}{t}f[x][i]
    f[y][j] it*j{k-t}$$
    (qquad qquad qquad qquad qquad qquad qquad qquad qquad Downarrow)
    $$f[x][i + j] = sum_{i = 0}^{size_x - 1}sum_{j = 0}^{size_y - 1} sum_{t = 0}kinom{k}{t}(f[x][i]*it) (f[y][j]
    j^{k-t})$$
    (qquad qquad qquad qquad qquad qquad qquad qquad qquad Downarrow)
    $$f[x][i + j] = sum_{t = 0}^kinom{k}{t}sum_{i = 0}^{size_x - 1}sum_{j = 0}^{size_y - 1} (f[x][i]i^t) (f[y][j]j^{k-t})$$
    (qquad qquad qquad qquad qquad qquad qquad qquad qquad Downarrow)
    $$f[x][i + j] = sum_{t = 0}^kinom{k}{t}sum_{i = 0}^{size_x - 1} (f[x][i]i^t)sum_{j = 0}^{size_y - 1} (f[y][j]j^{k-t})$$
    (qquad qquad qquad qquad qquad qquad qquad qquad qquad Downarrow)
    $$令g[x][t]表示sum_{i = 0}{size_x-1}f[x][i]*it,则上式转化为$$
    (qquad qquad qquad qquad qquad qquad qquad qquad qquad Downarrow)
    $$f[x][i + j] = sum_{t = 0}^kinom{k}{t}g[x][t]*g[y][k-t]$$

    • 我们发现实质上(f)的转移只与(g)有关,所以我们直接枚举指数(k)大小,(O(k))转移即可.

    • 上述讨论的是当(x,y)两点不都选的时候,如果都选,转移应当如下:

    [f[x][i + j + 1] = sum_{i = 0}^{size_x - 1}sum_{j=0}^{size_y-1} f[x][i] * f[y][j] * (i + j + 1) ^ k ]

    (qquad qquad qquad qquad qquad qquad qquad qquad qquad Downarrow)

    [f[x][i + j + 1] = sum_{i = 0}^{size_x - 1}sum_{j=0}^{size_y-1} f[x][i] * f[y][j] * (i + j + 1) ^ k ]

    (qquad qquad qquad qquad qquad qquad qquad qquad qquad Downarrow)

    [f[x][i + j + 1] = sum_{i = 0}^{size_x - 1}sum_{j=0}^{size_y-1} f[x][i] * f[y][j] * sum_{t = 0}^k(i+j)^t*1^{k-t}*inom{k}{t} ]

    (qquad qquad qquad qquad qquad qquad qquad qquad qquad Downarrow)

    [f[x][i + j + 1] = sum_{i = 0}^{size_x - 1}sum_{j=0}^{size_y-1}sum_{t = 0}^k f[x][i] * f[y][j] * (i+j)^t*inom{k}{t} ]

    (qquad qquad qquad qquad qquad qquad qquad qquad qquad Downarrow)

    [f[x][i + j + 1] = sum_{t = 0}^k inom{k}{t} sum_{i = 0}^{size_x - 1}sum_{j=0}^{size_y-1} f[x][i] * f[y][j] * (i+j)^t ]

    (qquad qquad qquad qquad qquad qquad qquad qquad qquad Downarrow)

    [f[x][i + j + 1] = sum_{t = 0}^k inom{k}{t} sum_{i = 0}^{size_x - 1}sum_{j=0}^{size_y-1} f[x][i] * f[y][j] * sum_{p = 0}^ti^p*j^{t-p}*inom{t}{p} ]

    (qquad qquad qquad qquad qquad qquad qquad qquad qquad Downarrow)

    [f[x][i + j + 1] = sum_{t = 0}^k inom{k}{t} sum_{i = 0}^{size_x - 1}sum_{j=0}^{size_y-1} sum_{p = 0}^t inom{t}{p}f[x][i] * f[y][j] * i^p*j^{t-p} ]

    (qquad qquad qquad qquad qquad qquad qquad qquad qquad Downarrow)

    [f[x][i + j + 1] = sum_{t = 0}^k inom{k}{t} sum_{p = 0}^t inom{t}{p}sum_{i = 0}^{size_x - 1}sum_{j=0}^{size_y-1} f[x][i] * f[y][j] * i^p*j^{t-p} ]

    (qquad qquad qquad qquad qquad qquad qquad qquad qquad Downarrow)

    [f[x][i + j + 1] = sum_{t = 0}^k inom{k}{t} sum_{p = 0}^t inom{t}{p}sum_{i = 0}^{size_x - 1} (f[x][i] * i^p) sum_{j=0}^{size_y-1} (f[y][j] *j^{t-p}) ]

    (qquad qquad qquad qquad qquad qquad qquad qquad qquad Downarrow)

    [f[x][i + j + 1] = sum_{t = 0}^k inom{k}{t} sum_{p = 0}^t inom{t}{p}g[x][p]*g[y][t-p] ]

    • 可以发现,最后的转移,依然是只与(g)有关.

    • 转移一个点是(O(k^2))的,(n)个点,故时间复杂度为(O(n * k^3/6)),实际上可以优化到(O(n*k^2))

    • 注意,我们如果有(a_1<a_2<cdots a_n 且 (1le a_i le m)),时间复杂度是(O(frac{n^m}{n!}))

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cctype>
    
    #define ll long long
    #define I register int
    #define L register ll
    #define F(i, a, b) for (L i = a; i <= b; i ++)
    #define mec(a, b) memcpy(a, b, sizeof a)
    #define mem(a, b) memset(a, b, sizeof a)
    #define add(a, b) ((a) = (a + b) % mo)
    #define N 100100
    #define M 2 * N
    #define Get getchar()
    #define mo 998244353
    
    using namespace std;
    
    ll n, m, K, u, v, ans, sum, h, x, k;
    ll F[N][11][2], G[N][11][2], jc[N], ny[N], d[N], bz[N];
    ll nex[M], tov[M], las[N], last[N], tot;
    
    void R(L &x) {
    	char c = Get; x = 0; L t = 1;
    	for (; !isdigit(c); c = Get) t = (c == '-' ? -1 : t);
    	for (; isdigit(c); x = (x << 3) + (x << 1) + c - '0', c = Get); x = x * t;
    }
    
    void W(L x) {
    	if (x < 0) { putchar('-'); W(-x); return; }
    	if (x > 9) W(x / 10); putchar(x % 10 + '0');
    }
    
    void ins(L x, L y) { tov[++ tot] = y, nex[tot] = las[x], las[x] = tot; }
    
    ll ksm(L x, L y) {
    	L ans = 1;
    	while (y) {
    		if (y & 1) ans = (ans * x) % mo;
    		x = (x * x) % mo, y >>= 1;
    	}
    	return ans;
    }
    
    ll C(L x, L y) { return jc[x] * ny[y] % mo * ny[x - y] % mo; }
    
    void Dg_dp() {
    	bz[1] = 1, d[h = 1] = 1;
    	while (h) { x = d[h], k = las[x];
    		if (k) {
    			if (!bz[tov[k]]) bz[tov[k]] = 1, d[++ h] = tov[k];
    			las[x] = nex[k];
    		}
    		if (!k) {
    			G[x][0][0] = G[x][0][1] = 1;
    			for (L k = last[x], y, s; k; k = nex[k])	
    				if ((y = tov[k]) && (!bz[y])) {
    					mem(F[x], 0);
    					F(j, 0, K)
    						F(k, 0, j) {
    							add(F[x][j][0], G[x][k][0] * (G[y][j - k][0] + G[y][j - k][1]) % mo * C(j, k));
    							add(F[x][j][1], G[x][k][1] * (G[y][j - k][0]) % mo * C(j, k)); s = 0;
    							F(p, 0, k) add(s, G[x][p][1] * G[y][k - p][1] % mo * C(k, p));
    							add(F[x][j][1], C(j, k) * s);
    						}
    				F(j, 0, K) G[x][j][0] = F[x][j][0], G[x][j][1] = F[x][j][1];
    			}
    			bz[d[h --]] = 0;
    		}
    			
    	}
    }
    
    int main() {
    	freopen("subgraph.in", "r", stdin);
    	freopen("subgraph.out", "w", stdout);
    	
    	R(n), R(m), R(K), jc[0] = ny[0] = 1;
    	F(i, 1, m) R(u), R(v), ins(u, v), ins(v, u);
    	F(i, 1, K) jc[i] = (jc[i - 1] * i) % mo, ny[i] = ksm(jc[i], mo - 2);
    	if (K == 0) { printf("%d", ksm(2, n)); return 0;}
    	mec(last, las), Dg_dp(), W((G[1][K][0] + G[1][K][1]) % mo);
    } 
    
  • 相关阅读:
    POJ 1321:棋盘问题
    POJ 2251:Dungeon Master
    POJ 3438:Look and Say
    POJ 1094:Sorting It All Out拓扑排序之我在这里挖了一个大大的坑
    杭电1285--确定比赛名次(拓扑排序)
    南阳67--三角形面积
    南阳38--布线问题
    杭电1050--Moving Tables(区间覆盖)
    杭电1217--Arbitrage(Spfa)
    杭电1719--Friend(找规律)
  • 原文地址:https://www.cnblogs.com/Pro-king/p/9383550.html
Copyright © 2011-2022 走看看