Codeforces Round #589 Div. 2 E. Another Filling the Grid 容斥原理

Codeforces Round #589 Div. 2 E. Another Filling the Grid 容斥原理

D居然没做出来。。智商是真跟不上

题意

n*n的格子填1~k的数字,保证每行每列至少一个1

思路

构造一个F(x)表示至少有x列没有1的满足条件的,则有:\(ans=f(0)-f(1)+f(2)...f(n)\)
想要容斥肯定要\(\binom{x}{i,x-i}\)列没有1满足条件的,剩下只需要乘上满足条件的个数就好了。
至于满足条件我们考虑首先要确保这\(\binom{x}{i,x-i}\)列没有1,\(f(x)=\binom{x}{i,x-i}*(k-1)^{i*n}*...\)剩下的部分考虑计算剩下的\(n-i\)列,这时我们开始按行考虑,则变成了n行,每行n-i个元素(什么为什么按行考虑?因为要确保每行有一个1)。则答案变成\(f(x)=\binom{x}{i,x-i}*(k-1)^{i*n}*((k)^{n-i}-(k-1)^{n-i})^{n}\)

代码

#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define PB push_back
#define ll long long
#define pii pair<int,int>
#define MEM(x,y) memset(x,y,sizeof(x))
#define bug(x) cout<<"debug "#x" is "<<x<<endl;
#define FIO ios::sync_with_stdio(false);
#define ALL(x) x.begin(),x.end()
ll n,m,k;
const ll mod=1e9+7;
ll c[355][355];
ll add(ll a,ll b){return (a+b)%mod;};
ll mul(ll a,ll b){return (a*b)%mod;};
ll sub(ll a,ll b){return (a-b+mod)%mod;};
void pre(){
    c[0][0]=1;
    for(int i=1;i<=300;i++)c[i][0]=c[i][i]=1;
    for(int i=2;i<=300;i++){
        for(int j=1;j<i;j++)c[i][j]=add(c[i-1][j-1],c[i-1][j]);
    }
}
ll ksm(ll r,ll d){
    ll res=1;
    while(d){
        if(d&1)res=mul(res,r);
        r=mul(r,r);
        d>>=1;
    }
    return res;
}

int main(){
    pre();
    cin>>n>>k;
    ll ans=0;
    for(ll i=0;i<=n;i++){
        ll val=mul(mul(c[n][i],ksm(ksm(k-1,n),i)),ksm(sub(ksm(k,n-i),ksm(k-1,n-i)),n));
        if(i%2==0)ans=add(ans,val);
        else ans=sub(ans,val);
    }
    cout<<ans<<endl;
}
posted @ 2019-09-30 10:40 zhangxianlong 阅读(...) 评论(...) 编辑 收藏