• [HNOI2019]多边形[二叉树建模、组合计数]


    题意

    题目链接

    分析

    不难发现终态一定是 ([2,n-2]) 中的每个点都与 (n) 连边。

    关于凸多边形的划分问题,可以将它看作一棵二叉树:每个树点可以看做点可以看做边。

    本题中看做点来处理,并将与 (n) 号点相连的所有节点看作一次分割(这些点之间一定有连边),每个分割出的区间(也是一棵树)里的根连到树的根。

    对于第一问,答案为 (n-3) 条边中未连接 (n) 号点的边数。容易构造一种方案达到下界:

    对于树的根,不同的子树每一步有且仅有一个位置满足可以旋转。这个点没有和 (n) 相连,且与 (n) 的连线 和 1 条线段相交。

    所以对每个非根节点有: (f_u=(s_u-1)!prod frac{f_v}{s_v!})

    对于根节点有:(f_{rt}=s_{rt}!prod frac{f_v}{s_v!})

    所以对于每个非根节点,在 (f_{rt}) 中的贡献都是 (frac{(s_u-1)!}{s_u!}=frac{1}{s_u})

    所以答案可以写成:(frac{ans1!}{prodlimits_{(l,r)in E,r e n}(r-l-1)})

    对于 (m) 个拓展状态,可以考虑删边和加边,(a,b,c,d) 中一定满足 (b)(c) 所有出边中的次小值, (d)(c) 所有出边中的最大值,所以每次确定 (b,d) 就可以 (O(1)) 了。

    复杂度 (O(n+m))

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    #define rep(i, a, b) for(int i = a; i <= b; ++i)
    inline int gi() {
        int x = 0,f = 1;
        char ch = getchar();
        while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar();}
        while(isdigit(ch)) { x = (x << 3) + (x << 1) + ch - 48; ch = getchar();}
        return x * f;
    }
    template <typename T> inline bool Max(T &a, T b){return a < b ? a = b, 1 : 0;}
    template <typename T> inline bool Min(T &a, T b){return a > b ? a = b, 1 : 0;}
    const int N = 1e5 + 7, mod = 1e9 + 7;
    int type, n, ans1, m, ans2 = 1;
    int inv[N], L[N], R[N], L2[N];
    void upd(int l, int r, int v) {
    	if(r == n) return;
    	if(v == 1) 
    		ans2 = (LL) ans2 * inv[r - l - 1] % mod * (++ans1) % mod;
    	else
    		ans2 = (LL) ans2 * (r - l - 1) % mod * inv[ans1--] % mod;
    }
    short num[100];
    void print(int x) {
    	short len = 0;
    	do {
    		num[len++] = x % 10;
    		x /= 10;
    	}while(x);
    	for(short i = len - 1; ~i; --i) putchar(num[i] + '0');
    }
    int main() {
    	type = gi(), n = gi();
    	inv[1] = 1;
    	rep(i, 2, n) inv[i] = (LL) (mod - mod / i) * inv[mod % i] % mod;
    	R[1] = n, L[n] = 1;
    	rep(i, 2, n - 1) L[i] = i - 1, L2[i] = i, R[i] = i + 1;
    	rep(i, 1, n - 3) {
    		int x = gi(), y = gi();
    		Max(R[x], y);
    		if(x < L[y]) {
    			L2[y] = L[y], L[y] = x;
    		}else Min(L2[y], x);
    		upd(x, y, 1);
    	}
    	m = gi();
    	print(ans1); if(type) putchar(' '), print(ans2); puts("");
    	while(m--) {
    		int a = gi(), c = gi(), b = L2[c], d = R[c];
    		upd(a, c, -1);
    		upd(b, d, 1);
    		print(ans1); if(type) putchar(' '), print(ans2); puts("");
    		upd(b, d, -1);
    		upd(a, c, 1);
    	}
    	return 0;
    }
    
  • 相关阅读:
    nvidia-smi电源显示ERR (Pwr:Usage ERR)
    阿里云windows安装ftp
    ansible常用模块
    ansible playbook
    ansible Inventory
    ansible安装
    ansible命令
    ansible配置文件
    js插件中提示框含有 或者<br/>显示不成换行怎么办,改样式
    [转] react项目安装及运行
  • 原文地址:https://www.cnblogs.com/yqgAKIOI/p/10792255.html
Copyright © 2020-2023  润新知