2018雅礼集训 方阵

方阵

给定 \(n × m\) 的矩阵,每个格子填上 \([1, c]\) 中的数字,求任意两行、两列均不同的方案数。

\(n, m ≤ 5000\)

题解

我们默认矩阵为 \(n\) 行的,以下将 \(n\) 视为常数。

\(g(m)\) 表示 \(m\) 列的矩阵,满足任意两行不相同的方案数。那么

\[ g(m)=(c^m)^\underline{n} \]

\(f_m(i)\) 表示 \(m\) 列的矩阵,满足任意两行不相同,且列总共分为 \(i\) 类的方案数。那么

\[ g(m)=\sum_{i=0}^m\begin{Bmatrix}m\\i\end{Bmatrix}f_m(i)\\ f_m(m)=\sum_{i=0}^m(-1)^{m-i}\begin{bmatrix}m\\i\end{bmatrix}g(i)\\ =\sum_{i=0}^m(-1)^{m-i}\begin{bmatrix}m\\i\end{bmatrix}(c^i)^\underline{n} \]

时间复杂度 \(O(nm)\)

CO int N=5000+10;
int S[N][N],P[N];

void real_main(){
    int n=read<int>(),m=read<int>(),c=read<int>();
    P[0]=1;
    for(int i=1;i<=m;++i) P[i]=mul(P[i-1],c);
    int ans=0;
    for(int i=1;i<=m;++i){
        int sum=S[m][i];
        for(int j=0;j<n;++j) cmul(sum,P[i]-j);
        cadd(ans,(m-i)&1?mod-sum:sum);
    }
    printf("%d\n",ans);
}
int main(){
    S[0][0]=1;
    for(int i=1;i<N;++i)for(int j=1;j<=i;++j)
        S[i][j]=add(S[i-1][j-1],mul(i-1,S[i-1][j]));
    for(int T=read<int>();T--;) real_main();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/12149566.html
今日推荐