zoukankan      html  css  js  c++  java
  • [2018雅礼集训1-16]方阵

    [题目描述]:

    给出一个 (n×m) 大小的矩形,每个位置可以填上$ [1,c]$中的任意一个数,要求填好后任意两行互不等价且任意两列互不等价,两行或两列等价当且仅当对应位置完全相同,求方案数 。

    (n,mle 5000)

    确实是一道神仙题。

    对这种行列都有限制的题我们可以先只考虑一边。

    我们先只考虑让行之间互不等价,一个(n行m列)且行互不等价的矩形的方案数为((C^m)^{underline{n}})

    我们设(g(m))表示行互不等价的情况下,(m)列的矩形的方案数。(g(m)=(C^m)^{underline{n}})

    我们设(f(m))表示行和列都分别互不等价的情况下,(m)列的矩形的方案数,也就是我们要的答案。

    则:

    [g(m)=sumlimits_{i=0}^megin{Bmatrix}m\i end{Bmatrix}f(i) ]

    这个式子的意义就是我们枚举(m)列分成了(i)个互不等价的集合,再将这(m)列分配到这些集合中去。

    由斯特林反演得到:

    [f(m)=sumlimits_{i=0}^m(-1)^{m-i}egin{bmatrix}m\i end{bmatrix}g(i) ]

    于是我们就可以(O(n^2))计算了。

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define mod 1004535809
    #define N 5005
    
    using namespace std;
    inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
    
    int T;
    ll n,m,c;
    ll s1[N][N],g[N];
    int main() {
    	s1[0][0]=1;
    	for(int i=1;i<=5000;i++)
    		for(int j=1;j<=5000;j++)
    			s1[i][j]=(s1[i-1][j-1]+(i-1)*s1[i-1][j])%mod;
    	T=Get();
    	while(T--) {
    		n=Get(),m=Get(),c=Get();
    		g[0]=1;
    		for(int i=1;i<=m;i++) g[i]=g[i-1]*c%mod;
    		ll ans=0;
    		int flag=m&1?1:-1;
    		for(int i=1;i<=m;i++,flag*=-1) {
    			ll now=1;
    			for(int j=1;j<=n;j++) now=now*(g[i]-j+1+mod)%mod;
    			(ans+=flag*s1[m][i]*now%mod+mod)%=mod;
    		}
    		cout<<ans<<"
    ";
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    C#-MessageBox全部函数重载形式及举例
    在软件开发中应用80:20原则
    C# 程序员最常犯的 10 个错误
    关于vs2013调试的偶然错误发现与总结(vs2013的承载进程)---ShinePans
    C#好书盘点
    C#中 父类与子类相互强制转换之实验
    如何用C#语言构造蜘蛛程序
    C#创建word,操作、读写
    Linux less/more命令详解
    Linux 环境变量详解
  • 原文地址:https://www.cnblogs.com/hchhch233/p/10016522.html
Copyright © 2011-2022 走看看