• bzoj2616. SPOJ PERIODNI(笛卡尔树+dp+组合数学)


    题目描述

    题解

    我们发现矩形是好做的,那么我们就把这个图形划分成若干的矩形。上下不太好搞的,所以我们根据上下来拆矩形。对序列建出笛卡尔树(小根堆),考虑一个点的贡献是其父亲到它的这一段长度内可以放的车,记 (f_{i,j}) 代表在 (i) 的子树内放 (j) 个车的方案数。首先先不考虑 (i) 的贡献,有 (f_{i,j}=sum_{k=0}^{j}f_{lson(i),k} imes f_{rson(i),k})。考虑 (i) 的贡献,即在一个 (n imes m) 的矩形内放 (k) 个点的方案数,容易算出是 ({n choose k} imes {m choose k} imes k!)。那么就简单了。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MAXN = 505;
    const ll mod = 1e9 + 7;
    struct treap{
    	int val, key, sz, son[2], fa;
    }tr[MAXN];
    int root;
    int n, k;
    int h[MAXN], stk[MAXN], top;
    ll f[MAXN][MAXN], fac[1000005], inv[1000005], ifac[1000005];
    ll C(ll i, ll j) {
    	if (i < 0 || j < 0 || i < j) return 0;
    	return fac[i] * ifac[j] % mod * ifac[i - j] % mod;
    }
    void dfs(int x) {
    	tr[x].sz = 1;
    	for (int i = 0; i < 2; i++) {
    		if (!tr[x].son[i]) continue;
    		tr[tr[x].son[i]].fa = x;
    		dfs(tr[x].son[i]);
    		tr[x].sz += tr[tr[x].son[i]].sz;
    	}
    	for (int j = 0; j <= k; j++) {
    		for (int w = 0; w <= j; w++) {
    			f[x][j] = (f[x][j] + f[tr[x].son[0]][w] * f[tr[x].son[1]][j - w] % mod) % mod;
    		}
    	}
    	for (int j = k; j >= 0; j--) {
    		for (int w = 1; w <= j; w++) {
    			f[x][j] = (f[x][j] + f[x][j - w] * fac[w] % mod * C(tr[x].sz - j + w, w) % mod * C(tr[x].key - tr[tr[x].fa].key, w) % mod) % mod;
    		}
    	}
    }
    int main() {
    	scanf("%d%d", &n, &k);
    	inv[0] = inv[1] = 1;
    	fac[0] = ifac[0] = 1;
    	for (int i = 2; i <= 1000000; i++) inv[i] = (mod - mod / i) * inv[mod % i] % mod;
    	for (int i = 1; i <= 1000000; i++) fac[i] = fac[i - 1] * i % mod, ifac[i] = ifac[i - 1] * inv[i] % mod;
    	for (int i = 1; i <= n; i++) {
    		tr[i].val = i;
    		scanf("%d", &tr[i].key);
    	}
    	for (int i = 1; i <= n; i++) {
    		while (top > 0 && tr[stk[top]].key > tr[i].key) {
    			int lst = stk[top];
    			top--;
    			if (top && tr[stk[top]].key > tr[i].key) tr[stk[top]].son[1] = lst;
    			else tr[i].son[0] = lst;
    		}
    		stk[++top] = i;
    	}
    	while (top > 1) {
    		tr[stk[top - 1]].son[1] = stk[top];
    		top--;
    	}
    	root = stk[1];
    	f[0][0] = 1;
    	dfs(root);
    	printf("%lld
    ", f[root][k]);
    	return 0;
    }
    

    一种更加好写的笛卡尔树建立方法:

    for (int i=1; i<=n; i++) {
        while (top>0&&a[stk[top]]>a[i]) ls[i]=stk[top--];
        if (top) rs[stk[top]]=i;
        stk[++top]=i;
    }
    root=stk[1];
    
  • 相关阅读:
    CLR基础
    Windows7下使用Shell32.dll出现没有实现接口的错误的解决办法
    Python学习
    Python学习
    开发常识之Linux用户及其权限管理
    (转)简单明晰的Jupyter Notebook总结与指南
    Oracle系列数据库版本区别
    应用场景区别-MongoDB与MySQL的选择比较
    我的博客(个人空间)地址更新说明
    (转)Spark与Map-Reduce区别对比
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/14326214.html
Copyright © 2020-2023  润新知