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;
    }
    
  • 相关阅读:
    萌新向Python数据分析及数据挖掘 第三章 机器学习常用算法 第三节 梯度下降法 (上)理解篇
    萌新向Python数据分析及数据挖掘 第三章 机器学习常用算法 第二节 线性回归算法 (下)实操篇
    萌新向Python数据分析及数据挖掘 第三章 机器学习常用算法 第二节 线性回归算法 (上)理解篇
    萌新向Python数据分析及数据挖掘 第三章 机器学习常用算法 第一节 KNN算法 (下)实操篇
    萌新向Python数据分析及数据挖掘 第三章 机器学习常用算法 第一节 KNN算法 (上)理解篇
    萌新向Python数据分析及数据挖掘 第二章 pandas 第五节 Getting Started with pandas
    Oracle数据库安装和授权
    c# 如何获取JSON文件以及如何获取Config文件(framework 和 net .Core)
    C#Core查询数据库存储EXCEL文件
    如何在WINDOW系统下编译P12证书制作
  • 原文地址:https://www.cnblogs.com/colazcy/p/14044525.html
Copyright © 2011-2022 走看看