【NOIP2014模拟10.25A组】放棋子

Description

【NOIP2014模拟10.25A组】放棋子_第1张图片

Solution

首先要保证每行每列至少要有一个,那么就容斥一下,枚举有多少行或列没有选。
因为枚举选不选行和列是相对独立的,那么假设枚举了i行,j列,那么要知道容斥系数 (1)(i+j)
然后枚举i,j之后,需要知道选出来的方案数 CinCjm
然后在剩下的行中随便搞,有两种方案:1、可以不填,2、不能不填
fjiij()
f[i][j]=f[i1][j1]+f[i1][j]j
1、 (c+1)!fc+1(ni)(mj) 加上一个c+1的颜色(空格),然后(c+1)中颜色再全排列。
2、 c!fc(ni)(mj) 原来的c种颜色,然后再全排列。
最后答案就是

i=0nj=0mCinCjm((c+1)!fc+1(ni)(mj)+c!fc(ni)(mj))

Code

#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=403,mo=1e9+7;
ll i,j,k,l,t,n,m,ans,c,fu;
ll fact[maxn],ni[maxn];
int f[maxn*maxn][maxn];
ll qsm(ll x,ll y){
    ll z=1;
    for(;y;y/=2,x=x*x%mo)if(y&1)z=z*x%mo;
    return z;
}
ll cc(ll x,ll y){return fact[x]*ni[y]%mo*ni[x-y]%mo;}
int main(){
    fact[0]=ni[0]=1;
    fo(i,1,400)fact[i]=fact[i-1]*i%mo;ni[400]=qsm(fact[400],mo-2);
    fod(i,399,1)ni[i]=ni[i+1]*(i+1)%mo;
    scanf("%d%d%d",&n,&m,&c);
    f[0][0]=1;
    fo(i,1,n*m){
        fo(j,1,min(c+1,i)){
            f[i][j]=(ll)(f[i-1][j-1]+f[i-1][j]*j%mo)%mo;
        }
    }
    fo(i,0,n){
        fo(j,0,m){
            fu=((i+j)%2)?-1:1;
            ans=(ans+cc(n,i)*cc(m,j)%mo*fu*(f[(n-i)*(m-j)][c+1]*fact[c+1]%mo+f[(n-i)*(m-j)][c]*fact[c]%mo)%mo)%mo;
        }
    }
    ans=(ans+mo)%mo;
    printf("%lld\n",ans);
}

你可能感兴趣的:(noip,数论,第二类斯特林数)