好久之前作的一道思博题了,今天来补一补。git
大体题意:在一个\(n*m\)的矩阵内填整数,数字在\([1,k]\)范围内。矩阵中某格的数为great number当且仅当与它同行同列的数字都严格比它小。记\(A_g\)为矩阵中恰有\(g\)个great number的填数方案数,求\(\sum_{g=0}^{nm}(g+1)\cdot A_g\)。(\(n,m,k\le200\))ui
首先咱们能够看出,上界一定是\(min(n,m)\),这个不解释了吧spa
而又有一个性质,\(\sum_{g=0}^{min(n,m)} A_g=K^{nm}\)。即全部的great number方案数等于总填数方案数code
因此咱们拆出\(\sum_{g=0}^{min(n,m)} A_g\)因而只须要考虑如何构造出\(\sum_{g=0}^{min(n,m)} g\cdot A_g\)it
咱们仍是回头再看一眼题面,\(g\)到底是什么:io
记\(A_g\)为矩阵中恰有\(g\)个great number的填数方案数class
那么每个great number在该方案下都对答案贡献\(1\)static
还不懂?再转化一步,也就是每一个格子上的数为great number的方案数之和di
这就是\(\sum_{g=0}^{min(n,m)} g\cdot A_g=nm\cdot\sum_{i=2}^k (i-1)^{n+m-2}\cdot k^{(n-1)\cdot (m-1)}\)while
而后各类乱搞就能够了
CODE
#include<cstdio> #include<cctype> using namespace std; const int mod=1e9+7; int t,n,m,k,ans; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); } inline int quick_pow(int x,int p) { long long tot=1; while (p) { if (p&1) tot=tot*1LL*x%mod; x=1LL*x*x%mod; p>>=1; } return (int)tot; } inline void inc(int &x,int y) { if ((x+=y)>=mod) x-=mod; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i,j; read(t); for (i=1;i<=t;++i) { read(n); read(m); read(k); for (ans=0,j=2;j<=k;++j) inc(ans,1LL*quick_pow(j-1,n+m-2)*quick_pow(k,n*m-n-m+1)%mod); ans=(1LL*ans*n*m)%mod; inc(ans,quick_pow(k,n*m)); printf("Case #%d: %d\n",i,ans); } return 0; }