2024.04.06 组合计数

2024/4/6 组合计数

CF128C - Games with Rectangle

给定一个 \(n\times m\) 的网格图,每次在当前矩形严格内部划定一个子矩形,划定 \(k\) 次,有多少种方案。

唯一性太明显了,显然答案就是

\[\binom{n-1}{2k}\binom{m-1}{2k} \]

#include <bits/stdc++.h>
using namespace std;
#define ld long double
template <typename T>
inline T read(){
    T x=0;char ch=getchar();bool fl=false;
    while(!isdigit(ch)){if(ch=='-')fl=true;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return fl?-x:x;
}
#define read() read<int>()
const int maxn = 1e3 + 10;
const int P = 1e9 + 7;
int fac[maxn],invfac[maxn],n,m,k;
int power(int a,int b){
    int res=1;
    while(b){
        if(b&1)res=1LL*a*res%P;
        a=1LL*a*a%P;
        b>>=1;
    }
    return res;
}
inline int C(int n,int m){
    if(m>n)return 0;
    return 1LL*fac[n]*invfac[m]%P*invfac[n-m]%P;
}
int main(){
    n=read();m=read();k=read();
    fac[0]=1;
    for(int i=1;i<=1000;i++)fac[i]=1LL*fac[i-1]*i%P;
    invfac[1000]=power(fac[1000],P-2);
    for(int i=1000;i>=1;i--)invfac[i-1]=1LL*invfac[i]*i%P;
    cout<<1LL*C(n-1,2*k)*C(m-1,2*k)%P<<endl;
    return 0;
}

CF111D - Petya and Coloring

给定一个 \(n\times m\) 的网格图,用 \(k\) 种颜色来对所有的格子染色。要求:

对于沿格子的线穿过的任何垂直线,会将棋盘分成两个非空的部分,这两个部分中的不同颜色的数量应相同。

\(n,m\leq 1000\)

题目条件等价为:随直线左右移动,左右两个颜色集合不变。

则中间 \(m-2\) 列元素只能染交集的颜色。

因此枚举第一列和最后一列的颜色交集为 \(i\) 种,第一列和最后一列颜色种数为 \(j\)\((j\geq i)\)

则答案为:

\[\sum_{i=0}^{n}\sum_{j=i}^{n}\binom{k}{i}\binom{k-i}{j-i}\binom{k-j}{j-i}(f_{n,j}\times j\ !)^2\times i^{n(m-2)} \]

#include <bits/stdc++.h>
using namespace std;
#define ld long double
template <typename T>
inline T read(){
    T x=0;char ch=getchar();bool fl=false;
    while(!isdigit(ch)){if(ch=='-')fl=true;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return fl?-x:x;
}
#define read() read<int>()
const int maxn = 1e6 + 10;
const int maxm = 1e3 + 10;
const int P = 1e9 + 7;
inline void add(int &x,int y){
    x+=y;
    if(x>=P)x-=P;
}
int fac[maxn],invfac[maxn],n,m,k;
int f[maxm][maxm];
int power(int a,int b){
    int res=1;
    while(b){
        if(b&1)res=1LL*a*res%P;
        a=1LL*a*a%P;
        b>>=1;
    }
    return res;
}
inline int C(int n,int m){
    if(n<0 || m<0)return 0;
    if(m>n)return 0;
    return 1LL*fac[n]*invfac[m]%P*invfac[n-m]%P;
}
inline void init(){
    fac[0]=1;
    for(int i=1;i<=1000000;i++)fac[i]=1LL*fac[i-1]*i%P;
    invfac[1000000]=power(fac[1000000],P-2);
    for(int i=1000000;i>=1;i--)invfac[i-1]=1LL*invfac[i]*i%P;
}
int main(){
    n=read();m=read();k=read();
    init();
    f[0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)add(f[i][j],f[i-1][j-1]),add(f[i][j],1LL*j*f[i-1][j]%P);
    }
    if(m==1){
        printf("%d\n",power(k,n));return 0;
    }
    int ans=0;
    for(int i=0;i<=n;i++){
        for(int j=i;j<=n;j++){
            int tmp1=1LL*C(k,i)*C(k-i,j-i)%P*C(k-j,j-i)%P;
            int tmp2=1LL*f[n][j]*fac[j]%P;tmp2=1LL*tmp2*tmp2%P;
            int tmp3=power(i,n*(m-2));
            add(ans,1LL*tmp1*tmp2%P*tmp3%P);
        }
    }
    printf("%d\n",ans);
    return 0;
}

CF886E. Maximum Element

计算题目所需的在中途跳出函数的排列数量容易算重,考虑补集转化。

\(f_i\) 表示长度为 \(i\) 的排列,不中途跳出函数的排列数量。

考虑最大的数 \(i\)\(i\) 的位置 \(j\in[i-k+1,i]\),因此枚举 \(j\) 进行统计。

\[f[i]=\sum_{j=i-k+1}^{i}\binom{i-1}{j-1}\times f[j-1] \times (i-j)!= (i-1)!\sum_{j=i-k+1}^{i}\frac{f_{j-1}}{(j-1)!} \]

则长度为 \(n\) 的所有答案为 \(n\) 的排列数为:

\[ans=\sum_{i=1}^{n}\binom{n-1}{i-1}\times f[i-1] \times (n-i)! \]

#include <bits/stdc++.h>
using namespace std;
#define ld long double
template <typename T>
inline T read(){
    T x=0;char ch=getchar();bool fl=false;
    while(!isdigit(ch)){if(ch=='-')fl=true;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return fl?-x:x;
}
#define read() read<int>()
const int maxn = 1e6 + 10;
const int P = 1e9 + 7;
inline void add(int &x,int y){
    x+=y;
    if(x>=P)x-=P;
}
int power(int a,int b){
    int res=1;
    while(b){
        if(b&1)res=1LL*res*a%P;
        a=1LL*a*a%P;
        b>>=1;
    }
    return res;
}
int fac[maxn],invfac[maxn],n,k;
int f[maxn],s[maxn];
inline int C(int n,int m){
    if(n<0 || m<0 || n<m)return 0;
    return 1LL*fac[n]*invfac[n-m]%P*invfac[m]%P;
}
int main(){
    n=read();k=read();
    fac[0]=1;
    for(int i=1;i<=1000000;i++)fac[i]=1LL*fac[i-1]*i%P;
    invfac[1000000]=power(fac[1000000],P-2);
    for(int i=1000000;i>=1;i--)invfac[i-1]=1LL*invfac[i]*i%P;
    f[0]=1;s[0]=1;
    for(int i=1;i<=n;i++){
        int Lj=max(0,i-k),Rj=i-1;
        int tmp;
        if(!Lj)tmp=s[Rj];
        else tmp=(s[Rj]-s[Lj-1]+P)%P;
        add(f[i],1LL*fac[i-1]*tmp%P);
        add(s[i],1LL*f[i]*invfac[i]%P);
        add(s[i],s[i-1]);
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        add(ans,1LL*C(n-1,i-1)*f[i-1]%P*fac[n-i]%P);
    }
    ans=(fac[n]-ans+P)%P;
    cout<<ans<<endl;
    return 0;
}
posted @ 2024-04-07 00:06  ¶凉笙  阅读(13)  评论(0编辑  收藏  举报