zoukankan      html  css  js  c++  java
  • 【模考】2018.03.10 图

    【问题描述】

    enter image description here
    一个图被认为是刚体,如果该图无法只改变其中一部分的形状,而使得余下的部分的形状保持不变。
    例如上图中的 (a) (b) (c) 都是刚体。

    为了简化问题,我们现在只考虑 n × m 的格点图。
    enter image description here
    上图不是刚体,但是可以通过在对角线加入支撑的方式使得其变为刚体。
    enter image description here
    我们的问题是,对于 m × n 的个点图,有多少种添加支撑的方案可以使其变为刚体?
    注意本题在每个小矩形中,我们至多只允许添加一个方向的对角线。
    例如,对于 2 × 3 的格点图,一共有 448 种方案。

    【输入格式】

    从文件 graph.in 中读入数据.
    (T)
    (n_1) (m_1)
    (vdots)
    (n_T) (m_T)

    【输出格式】

    输出到文件 graph.out 中.
    输出共 T 个整数,表示方案数。

    【样例输入】

    4
    1 2
    3 2
    7 9
    10 10

    【样例输出】

    4
    448
    357533852
    935300639

    【子任务】

    对于 20% 的数据 n ≤ 4, m ≤ 4
    对于另 20% 的数据 n = 1 或 m = 1
    对于另 20% 的数据 n ≤ 10, m ≤ 10
    对于另 20% 的数据 n ≤ 30, m ≤ 30
    对于 100% 的数据 n ≤ 100, m ≤ 100, T ≤ 5

    【正解】

    一开始我们会认为只要每行每列存在至少一个支架就能够支撑,但其实是不对的
    我们把最开始的图看作是一团乱麻,不要看作是规则的。然后我们每加入一个支架,就是使一行的竖边和一列的横边垂直。我们最后需要的状态是所有竖边和横边垂直
    在最开始的想法中,虽然每行每列都有垂直,但是有可能是错开的扭曲的垂直
    回到思路上来,考虑建出一个二分图(G_{n,m}),答案就是使得二分图(G_{n,m})联通的方案数
    再设计dp
    (f[i][j])表示(G_{i,j})的联通方案数
    转移方程:

    [f[i][j]=3^{ij}-sum_{k=1}^isum_{l=0}^jC_{i-1}^{k-1}C_{j}^{l}f[k][l]3^{(i-k)(j-l)} ]

    (3^{ij})是二分图所有情况的总数,再算出不合法情况,进行容斥
    考虑枚举一号点所在联通块大小
    (sum_{k=1}^i)是在枚举左边部分(i)个点包括一号点在内总共有(k)个点与一号点联通
    (sum_{l=0}^j)则是在枚举右边
    (C_{i-1}^{k-1}C_{j}^{l})是指左边要有(k)个点,那么要从二号点到(i)号点中选(k-1)个点出来,右边同理
    (3^{(i-k)(j-l)})是因为我们保证了一号点所在的联通块不会再和其他点联通,所以剩下的点随便怎么连,总共有(3^{(i-k)(j-l)})方案数
    这样转移,还要注意一些小细节,要预处理组合数,预处理3的幂

    #include<bits/stdc++.h>
    #define ll long long
    const int Mod=1e9+7,MAXN=100+10;
    int T;
    ll f[MAXN][MAXN],C[MAXN][MAXN],exp3[MAXN*MAXN];
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char c='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(c!='')putchar(c);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    inline ll qexp(ll a,ll b)
    {
    	ll res=1;
    	while(b)
    	{
    		if(b&1)res=res*a%Mod;
    		a=a*a%Mod;
    		b>>=1;
    	}
    	return res;
    }
    inline void init()
    {
    	exp3[0]=1;
    	for(register int i=1;i<MAXN*MAXN;++i)exp3[i]=exp3[i-1]*3%Mod;
    	C[0][0]=1;
    	for(register int i=1;i<MAXN;++i)
    	{
    		C[i][0]=1;
    		for(register int j=1;j<MAXN;++j)C[i][j]=(C[i-1][j]+C[i-1][j-1])%Mod;
    	}
    	f[1][0]=f[0][1]=1;
    	for(register int i=1;i<MAXN;++i)
    		for(register int j=1;j<MAXN;++j)
    		{
    			f[i][j]=exp3[i*j];
    			ll res=0;
    			for(register int k=1;k<=i;++k)
    				for(register int l=0;l<=j;++l)
    					if(k==i&&l==j)break;
    					else(res+=exp3[(i-k)*(j-l)]*C[i-1][k-1]%Mod*C[j][l]%Mod*f[k][l]%Mod)%=Mod;
    			f[i][j]=(f[i][j]-res+Mod)%Mod;
    		}
    }
    int main()
    {
    	freopen("graph.in","r",stdin);
    	freopen("graph.out","w",stdout);
    	read(T);
    	init();
    	while(T--)
    	{
    		int n,m;
    		read(n);read(m);
    		write(f[n][m],'
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    程序自动更新版本
    [.NET] Rough Dependency Injection
    Python标准库存储对象(pickle包,cPickle包)
    发送邮件,支持群发
    css3传送带示例
    “计算机之子”的MVVM框架源码学习笔记
    Windows 8 应用商店正式面向全部开发者开放
    MVVM框架 v1发布
    Python学习索引
    注册 windows 8 开发者账号
  • 原文地址:https://www.cnblogs.com/hongyj/p/8540815.html
Copyright © 2011-2022 走看看