Codeforces 1228E. Another Filling the Grid

传送门

看到 $n=250$ 显然考虑 $n^3$ 的 $dp$

设 $f[i][j]$ 表示填完前 $i$ 行,目前有 $j$ 列的最小值是 $1$ 的合法方案数

那么对于 $f[i][j]$ ,枚举 $f[i-1][k]$ ,有 $f[i][j]=\sum_{k=0}^{j}\binom{n-k}{j-k}f[i-1][k](m-1)^{n-j}m^k$

这里 $m$ 就是题目的 $k$

$\binom{n-k}{j-k}$ 是因为多出来的 $j-k$ 列 $1$ 可以任选

$(m-1)^{n-j}$ 是保证没有 $1$ 的列不能填 $1$ ,只有 $m-1$ 种填的数

$m^k$ 是那些原本有保证为 $1$ 的列怎么填都行

当然剩下的那 $j-k$ 个位置显然都是 $1$ ,方案数只有 $1$

然后这样就可以做到 $n^3 \log n$ 然后发现竟然 $T$ 了,所以预处理一下 $k \in [0,n],m^k$ 和 $k \in [0,n],(m-1)^k$ 即可

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) f=-1; ch=getchar(); }
    while(ch>=‘0‘&&ch<=‘9‘) { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int mo=1e9+7,N=507;
inline int fk(int x) { return x>=mo ? x-mo : x; }
int n,m;
int C[N][N],f[N][N];
int mi[N],mi_1[N];
int main()
{
    n=read(),m=read();
    for(int i=0;i<=n;i++)
    {
        C[i][0]=1;
        for(int j=1;j<=i;j++)
            C[i][j]=fk(C[i-1][j]+C[i-1][j-1]);
    }
    mi[0]=mi_1[0]=1;
    for(int i=1;i<=n;i++)
    {
        mi[i]=1ll*mi[i-1]*m%mo;
        mi_1[i]=1ll*mi_1[i-1]*(m-1)%mo;
    }
    for(int j=1;j<=n;j++) f[1][j]=1ll*C[n][j]*mi_1[n-j]%mo;
    for(int i=2;i<=n;i++)
        for(int j=0;j<=n;j++)
        {
            for(int k=0;k<=j;k++)
            {
                int x=1ll*f[i-1][k]*C[n-k][j-k]%mo;
                int y=1ll*mi_1[n-j]*mi[k]%mo;
                f[i][j]=fk(f[i][j]+1ll*x*y%mo);
                if(j==k) f[i][j]=fk(f[i][j]-1ll*mi_1[n]*f[i-1][k]%mo+mo);
            }
        }
    printf("%d\n",f[n][n]);
    return 0;
}

正常的做法

但是有些神仙看完数据说:" $n$ 太小了,可以出到 $10^5$ 级别"

所以考虑一下神仙的做法

看到有限制的方案数,考虑容斥!

总方案 - (一行不合法+一列不合法) + (两行不合法+两列不合法+一行一列不合法) - ......

那么写成式子就是长这个样子:

$\sum_{i=0}^{n}\sum_{j=0}^{n}(-1)^{i+j} \binom{n}{i}\binom{n}{j}m^{n^2-n(i+j)+ij}(m-1)^{n(i+j)-ij}$

上面 $m^{n^2-n(i+j)+ij}$ 就是没限制的位置顺便填,$(m-1)^{n(i+j)-ij}$ 就是强制 $i$ 行 $j$ 列的格子不能填 $1$

然后同样预处理一下 $m$ 和 $m-1$ 的幂次就可以做到 $n^2$

对着这个式子继续搞:

$\sum_{i=0}^{n}\sum_{j=0}^{n}(-1)^{i+j} \binom{n}{i}\binom{n}{j}m^{n^2-n(i+j)+ij}(m-1)^{n(i+j)-ij}$

$\sum_{i=0}^{n}(-1)^i\binom{n}{i}\sum_{j=0}^{n}(-1)^j\binom{n}{j}m^{(n-i)(n-j)}(m-1)^{(n-i)j}(m-1)^{ni}$

$\because \sum_{j=0}^{n}(-1)^j\binom{n}{j}m^{(n-i)(n-j)}(m-1)^{(n-i)j}=(m^{n-i}-(m-1)^{n-i})^n$

$\therefore \sum_{i=0}^{n}(-1)^i\binom{n}{i}(m-1)^{ni}(m^{n-i}-(m-1)^{n-i})^n$

$\sum_{i=0}^{n}(-1)^i\binom{n}{i}(m^{n-i}(m-1)^i-(m-1)^n)^n$

然后就可以 $n \log n$ 解决了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) f=-1; ch=getchar(); }
    while(ch>=‘0‘&&ch<=‘9‘) { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=507,mo=1e9+7;
inline int fk(int x) { return x>=mo ? x-mo : x; }
int n,m,Ans;
int C[N][N],mi[N],m_1i[N];
inline int ksm(int x,int y)
{
    int res=1;
    while(y) { if(y&1) res=1ll*res*x%mo; x=1ll*x*x%mo; y>>=1; }
    return res;
}
int main()
{
    n=read(),m=read();
    for(int i=0;i<=n;i++)
    {
        C[i][0]=1;
        for(int j=1;j<=i;j++) C[i][j]=fk(C[i-1][j]+C[i-1][j-1]);
    }
    mi[0]=m_1i[0]=1;
    for(int i=1;i<=n;i++)
    {
        mi[i]=1ll*mi[i-1]*m%mo;
        m_1i[i]=1ll*m_1i[i-1]*(m-1)%mo;
    }
    for(int i=0;i<=n;i++)
    {
        int t=1ll*C[n][i]*ksm( fk(1ll*mi[n-i]*m_1i[i]%mo - m_1i[n] +mo) , n )%mo;
        i&1 ? Ans=fk(Ans-t+mo) : Ans=fk(Ans+t);
    }
    printf("%d\n",Ans);
    return 0;
}

原文地址:https://www.cnblogs.com/LLTYYC/p/11612535.html

时间: 2024-08-30 13:29:45

Codeforces 1228E. Another Filling the Grid的相关文章

[Codeforces 1228E]Another Filling the Grid (排列组合+容斥原理)

[Codeforces 1228E]Another Filling the Grid (排列组合+容斥原理) 题面 一个\(n \times n\)的格子,每个格子里可以填\([1,k]\)内的整数.要保证每行每列的格子上的数最小值为1,有多少种方案 \(n \leq 250,k \leq 10^9\) 分析 这题有\(O(n^3)\)的dp做法,但个人感觉不如\(O(n^2 \log n)\)直接用数学方法求更好理解. 考虑容斥原理,枚举有\(i\)行最小值>1,有\(j\)行最小值>1,那

Another Filling the Grid

E. Another Filling the Grid 参考:Codeforces Round #589 (Div. 2)-E. Another Filling the Grid-容斥定理 容斥这个东西可以理解,但是运用到实际的时候,还是觉得有点迷迷糊糊的,不知道套公式会不会是一种可行的办法. 是时候也得把以前的知识温习一下了.... 具体的思路看参考的博客就可以理解了. 代码: // Created by CAD on 2019/10/2. #include <bits/stdc++.h>

Codeforces Round #589 (Div. 2) B——B. Filling the Grid

Suppose there is a h×wh×w grid consisting of empty or full cells. Let's make some definitions: riri is the number of consecutive full cells connected to the left side in the ii-th row (1≤i≤h1≤i≤h). In particular, ri=0ri=0 if the leftmost cell of the 

B. Filling the Grid codeforces

题目链接:https://codeforces.com/contest/1228/problem/B #include <cstdio> #include <algorithm> #include <iostream> #include <vector> #include <cstring> #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; string a[1005]; co

Codeforces Round #589 (Div. 2) Another Filling the Grid (dp)

题意:问有多少种组合方法让每一行每一列最小值都是1 思路:我们可以以行为转移的状态 附加一维限制还有多少列最小值大于1 这样我们就可以不重不漏的按照状态转移 但是复杂度确实不大行(减了两个常数卡过去的...) #include <bits/stdc++.h> using namespace std; const int inf = 0x3f3f3f3f; const double eps = 1e-6; const int N = 3e5+7; typedef long long ll; co

E. Another Filling the Grid 状压dp

http://codeforces.com/contest/1228/my 题意:有个nm的矩形  每个格子可以取1-k中的一种数字  问有多少种填法  使得每行每列至少都有一个1 题解:设置dp[i][j] 表示 当前处理到i行有j列为1的方案数   然后统计答案贡献即可   注意改行至少取一个1 #include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=(a);i<=(b);i++) #defi

codeforces 680E Bear and Square Grid 巧妙暴力

这个题是个想法题 先预处理连通块,然后需要用到一种巧妙暴力,即0变1,1变0,一列列添加删除 复杂度O(n^3) #include <cstdio> #include <iostream> #include <ctime> #include <vector> #include <cmath> #include <map> #include <queue> #include <algorithm> #includ

codeforces 356C Bear and Square Grid

#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> using namespace std; char mp[510][510]; int vis[510][510]; int are_num[510][510]; int sum[510][510]; int

CF1228E Another Filling the Grid

Description 题目链接 把 \(k\) 个数填进 \(n\times n\) 的网格中,要求每行每列的最小值均为 \(1\) ,求合法方案数对 \(10^9+7\) 取模的结果 \(1\le n\le 250,1\le k\le 10^9\) Solution 看着标签是 \(\text{combinatorics}\) 和 \(\text{dp}\) 就看了看题目...... 考虑从左向右 \(\text{dp}\) ,每列至少有一个 \(1\) ,同时考虑行的情况.对于某一列如果填