zoukankan      html  css  js  c++  java
  • 题解 P6453 【[COCI2008-2009#4] F】

    题目链接

    Solution [COCI2008-2009#4] F

    题目大意:给定一个 (n) 列的表格,每一列有 (a_i) 行,底部对齐。往里面填入 (k) 个数字,要求每一列最多只有一个数字,每一行一段内最多只有一个数字(中间断开了不算),求方案数。

    笛卡尔树,dp,计数


    分析:

    最大子矩形可以用笛卡尔树来做,此题每一段中间断开的特性,和小根笛卡尔树构造方法也十分相似(每次我们找到最低的一列分开原表格)。

    我们将原表格建出一个小根笛卡尔树,那么笛卡尔树的每一个节点都代表了一个子矩形(具体可以看一下其他题解,这里就不重复放图了)

    我们设 (w(u,a,b)),表示在 (u) 这个节点所在子矩形内部,放 (a) 个数,其中 (u) 的子树选了 (b) 个的方案数。

    那么这个子矩形的宽 (n=v[u]-v[faz[u]]),这个子矩形的长(是实际可以选的列数) (m=siz[u]-b)

    其中选 (k) 个行列互不相同的数,方案数为 (inom{n}{k}inom{m}{k}k!)(相当于行列中任选 (k) 个出来,再任意组合)

    然后直接两个子树的方案数卷一下,再和 (w) 卷一下就可以了

    注意合并的时候要用 (siz) 优化,确保每一对节点只会在 (lca) 处被合并(貌似和 (w) 卷的时候并不能优化)

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #pragma GCC optmize(2)
    using namespace std;
    typedef long long ll;
    constexpr int maxn = 512,inf = 0x7fffffff,mod = 1e9 + 7;
    struct IO{//-std=c++11,with cstdio and cctype
    	private:
    		static constexpr int ibufsiz = 1 << 20;
    		char ibuf[ibufsiz + 1],*inow = ibuf,*ied = ibuf;
    		static constexpr int obufsiz = 1 << 20;
    		char obuf[obufsiz + 1],*onow = obuf;
    		const char *oed = obuf + obufsiz;
    	public:
    		inline char getchar(){
    			#ifndef ONLINE_JUDGE
    				return ::getchar();
    			#else
    				if(inow == ied){
    					ied = ibuf + sizeof(char) * fread(ibuf,sizeof(char),ibufsiz,stdin);
    					*ied = '';
    					inow = ibuf;
    				}
    				return *inow++;
    			#endif
    		}
    		template<typename T>
    		inline void read(T &x){
    			static bool flg;flg = 0;
    			x = 0;char c = getchar();
    			while(!isdigit(c))flg = c == '-' ? 1 : flg,c = getchar();
    			while(isdigit(c))x = x * 10 + c - '0',c = getchar();
    			if(flg)x = -x;
    		}
    		template <typename T,typename ...Y>
    		inline void read(T &x,Y&... X){read(x);read(X...);}
    		inline int readi(){static int res;read(res);return res;}
    		inline long long readll(){static long long res;read(res);return res;}
    		
    		inline void flush(){
    			fwrite(obuf,sizeof(char),onow - obuf,stdout);
    			fflush(stdout);
    			onow = obuf;
    		}
    		inline void putchar(char c){
    			#ifndef ONLINE_JUDGE
    				::putchar(c);
    			#else
    				*onow++ = c;
    				if(onow == oed){
    					fwrite(obuf,sizeof(char),obufsiz,stdout);
    					onow = obuf;
    				}
    			#endif
    		}
    		template <typename T>
    		inline void write(T x,char split = ''){
    			static unsigned char buf[64];
    			if(x < 0)putchar('-'),x = -x;
    			int p = 0;
    			do{
    				buf[++p] = x % 10;
    				x /= 10;
    			}while(x);
    			for(int i = p;i >= 1;i--)putchar(buf[i] + '0');
    			if(split != '')putchar(split);
    		}
    		inline void lf(){putchar('
    ');}
    		~IO(){
    			fwrite(obuf,sizeof(char),onow - obuf,stdout);
    		}
    }io;
    template <typename A,typename B>
    inline void chkmin(A &x,const B &y){if(y < x)x = y;}
    template <typename A,typename B>
    inline void chkmax(A &x,const B &y){if(y > x)x = y;}
    
    inline int add(const int a,const int b){return (a + b) % mod;}
    inline int mul(const int a,const int b){return (1ll * a * b) % mod;}
    inline int qpow(int base,int b){
    	int res = 1;
    	while(b){
    		if(b & 1)res = mul(res,base);
    		base = mul(base,base);
    		b >>= 1;
    	}
    	return res;
    }
    inline int inv(const int x){return qpow(x,mod - 2);}
    inline int calc(const int a,const int b){return mul(a,inv(b));}
    
    int fac[int(1e6 + 100)];
    inline int C(const int n,const int m){
    	return m > n ? 0 : mul(fac[n],mul(inv(fac[m]),inv(fac[n - m])));
    }
    inline void init(){
    	fac[0] = 1;
    	for(int i = 1;i < (1e6 + 100);i++)fac[i] = mul(fac[i - 1],i);
    }
    
    int tmp[maxn],faz[maxn],val[maxn],stk[maxn],siz[maxn],ls[maxn],rs[maxn],f[maxn][maxn],top,k,n;
    inline int w(const int u,const int a,const int b){
    	const int n = val[u] - val[faz[u]],m = siz[u] - b;
    	return mul(mul(C(n,a),C(m,a)),fac[a]);
    }
    inline void dp(int u){
    	siz[u] = 1;
    	if(ls[u])faz[ls[u]] = u,dp(ls[u]);
    	if(rs[u])faz[rs[u]] = u,dp(rs[u]);
    	siz[u] += siz[ls[u]];
    	siz[u] += siz[rs[u]];
    	memset(tmp,0,sizeof(tmp));
    	for(int i = 0;i <= siz[ls[u]];i++)
    		for(int j = 0;j <= siz[rs[u]];j++)
    			if(i + j <= k)tmp[i + j] = add(tmp[i + j],mul(f[ls[u]][i],f[rs[u]][j]));
    	tmp[0] = 1;
    	for(int i = 0;i <= siz[u];i++)
    		for(int j = 0;i + j <= siz[u];j++)
    			if(i + j <= k)f[u][i + j] = add(f[u][i + j],mul(tmp[i],w(u,j,i)));
    }
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("fafa.in","r",stdin);
    #endif
    	init();
    	io.read(n,k);
    	for(int i = 1;i <= n;i++)io.read(val[i]);
    	for(int i = 1;i <= n;i++){
    		int k = top;
    		while(k && val[i] <= val[stk[k]])k--;
    		if(k)rs[stk[k]] = i;
    		if(k < top)ls[i] = stk[k + 1];
    		stk[++k] = i;
    		top = k;
    	}
    	int rt = stk[1];
    	f[0][0] = 1;
    	dp(rt);	
    	io.write(f[rt][k],'
    ');
    	return 0;
    }
    
  • 相关阅读:
    hadoop常用命令详细解释
    2019-05-20 Sublime Text 编辑
    2019-05-20 什么是分布式系统、分布式锁
    2019-05-19 centos7下删掉一个目录下所有的文件
    2019-05-17 ABRT has detected 1 problem(s). For more info run: abrt-cli list --since 1558053651
    2019-05-17 java.net.BindException: Address already in use: JVM_Bind <null>:8083
    2019-05-16mysql忘记密码怎么办
    2019-05-16查看MySQL版本sql语句
    2019-05-15 cenots7动态IP地址改为静态
    2019-05-14 MySQL通过dos命令操作数据库
  • 原文地址:https://www.cnblogs.com/colazcy/p/14044525.html
Copyright © 2011-2022 走看看