码迷,mamicode.com
首页 > 其他好文 > 详细

[2018雅礼集训1-16]方阵

时间:2018-11-25 20:30:44      阅读:272      评论:0      收藏:0      [点我收藏+]

标签:计算   mod   for   情况   int   i++   std   就是   include   

[题目描述]:

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

\(n,m\le 5000\)

确实是一道神仙题。

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

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

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

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

则:
\[ g(m)=\sum\limits_{i=0}^m\begin{Bmatrix}m\\i \end{Bmatrix}f(i) \]
这个式子的意义就是我们枚举\(m\)列分成了\(i\)个互不等价的集合,再将这\(m\)列分配到这些集合中去。

由斯特林反演得到:
\[ f(m)=\sum\limits_{i=0}^m(-1)^{m-i}\begin{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<<"\n";
    }
    return 0;
}

[2018雅礼集训1-16]方阵

标签:计算   mod   for   情况   int   i++   std   就是   include   

原文地址:https://www.cnblogs.com/hchhch233/p/10016522.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!