topcoder13444
CountTables
sol:题意和题解都丢在上面了,自己XJByy了一下
先保证行不同,然后对列容斥,dp[i]表示i列的答案
行不同时i列的答案显然是C(c^i,n)*n!,然后在把列之间相同的去掉,就是把i列分为[1~i-1]组,钦定各组之间互不相同,就是第二类斯特林数,减去S[i][ j=[1,i-1] ]*dp[j]即可
/* 问有多少n*m的矩阵,每个数都在[1,C]内,任两行不完全相同,任两列不完全相同。 */ #include <bits/stdc++.h> using namespace std; typedef long long ll; inline ll read() { ll s=0; bool f=0; char ch=' '; while(!isdigit(ch)) {f|=(ch=='-'); ch=getchar();} while(isdigit(ch)) {s=(s<<3)+(s<<1)+(ch^48); ch=getchar();} return (f)?(-s):(s); } #define R(x) x=read() inline void write(ll x) { if(x<0) {putchar('-'); x=-x;} if(x<10) {putchar(x+'0'); return;} write(x/10); putchar((x%10)+'0'); } #define W(x) write(x),putchar(' ') #define Wl(x) write(x),putchar('\n') const ll Mod=1000000007; const int N=4005; ll n,m,c,dp[N]; //先保证行不同,然后对列容斥,dp[i]表示i列的答案 //行不同时i列的答案显然是C(c^i,n)*n! ll S[N][N],fac[N],invf[N]; inline ll Ksm(ll x,ll y) { ll ans=1; while(y) { if(y&1) ans=ans*x%Mod; x=x*x%Mod; y>>=1; } return ans; } int main() { int i,j; R(n); R(m); R(c); fac[0]=1; for(i=1;i<=max(n,m);i++) fac[i]=fac[i-1]*i%Mod; invf[m]=Ksm(fac[m],Mod-2); for(i=m-1;i>=0;i--) invf[i]=invf[i+1]*(i+1)%Mod; S[0][0]=1; for(i=1;i<=m;i++) for(j=1;j<=i;j++) S[i][j]=(S[i-1][j-1]+S[i-1][j]*j%Mod)%Mod; ll oo=1,now; for(i=1;i<=m;i++) { oo=oo*c%Mod; now=1; for(j=1;j<=n;j++) now=now*(oo-j+1)%Mod; for(j=1;j<i;j++) now=(now-S[i][j]*dp[j]%Mod+Mod)%Mod; dp[i]=now; } Wl(dp[m]); return 0; } /* input 2 2 2 output 10 input 1 1 4000 output 4000 input 4000 4000 4000 output 237003303 input 5 5 1 output 0 input 4000 1 4000 output 593395757 input 2 3 5 output 13740 */
河田は河田、赤木は赤木……。
私は誰ですか。教えてください、私は誰ですか。
そうだ、俺はあきらめない男、三井寿だ!