组合数学之TwelveFold Way

组合数学之TwelveFold Way

题目传送


LLC

  • n个球有标号,m个盒子有标号,每个盒子至多放一个球
  • 如果 \(n>m,ans=0\) - 否则为 \(ans=A^n_m=C_m^n\cdot A_n^n\),相当于是先从 \(m\) 个盒子取出 \(n\)个盒子,再全排因为球有编号

LLA

  • n个球有标号,m个盒子有标号,盒子没有限制 - 那么每个球都有 \(m\) 种选择 - \(ans=m^n\)

LLB

  • n个球有编号,m个盒子有编号,每个盒子至少放一个球 - 如果 \(n<m,ans=0\)
  • 否则,我们强制有 \(i\) 个盒子为空,其他盒子乱放,需要容斥一下。
  • 首先向LLA一样,答案有 \(m^n\) ,但是这里边含有盒子为空的情况。把一个盒子为空两个盒子为空三个盒子为空...的情况都减掉,但是一个盒子为空里边又包含两个盒子为空三个盒子为空....的情况,会减多,我们加回来两个盒子为空的情况 \[ans=\sum_{i=0}^m(-1)^i \cdot C_m^i \cdot (m-i)!\]

LUC

  • n个球有标号,m个盒子无标号,每个盒子至多放一个球
  • 如果 \(n>m,ans=0\) - 否则为 \(ans=1\)

LUB

  • n个球有标号,m个盒子无标号,每个盒子至少放一个球
  • 我们考虑 DP,设 \(f[i][j]\) 表示前 \(i\) 个球放在 \(j\) 个盒子里的方案数\[f[i][j]=f[i-1][j-1]+j \cdot f[i-1][j]\]
  • 因为球有编号,这样顺序DP 起了去重的作用
  • 第二类斯特林数的递推公式 \[S_n^m=s_{n-1}^{m-1}+m\cdot S_{n-1}^{m}\]

LUA

  • n个球有标号,m个盒子无标号,盒子无限制 - 我们可以利用LUB,然后枚举空盒子的数量 \[ans=\sum_{i=1}^mf[n][i]\]

ULC

  • n个球无标号,m个盒子有标号,每个盒子至多放一个球
  • 如果 \(n>m,ans=0\) - 否则为 \(ans=1\)

ULB

  • n个球无标号,m个盒子有标号,每个盒子至少放一个球
  • 隔板法 \[ans=C_{n-1}^{m-1}\]

ULA

  • n个球无标号,m个盒子有标号,盒子无限制
  • 还是隔板法,不过强制几个盒子为空 \[ans=\sum_{i=1}^{m}C_{n-1}^{i-1} \cdot C_{m}^{i}\]
  • 不要忘记乘强制选盒子的方案数

UUC

  • n个球无标号,m个盒子无标号,每个盒子至多放一个球
  • 如果 \(n>m,ans=0\)
  • 否则为 \(ans=1\)

UUB

  • n个球无标号,m个盒子无标号,每个盒子至少放一个球
  • 这个不能用隔板法,因为划分出相同数量的盒子,盒子没有编号是相同的。
  • 我们考虑DP,设 \(f[i][j]\) 表示前 \(i\) 个球分到 \(j\) 个盒子里
  • 为了保证不重,我们保证盒子里球的数量单调不降
  • 转移 \[f[i][j]=f[i-1][j-1]+f[i-j][j-1]\]
  • 对于当前的球要么新开一个盒子,要么再之前的盒子基础上都放进去一个
  • 划分数

UUA

  • 对UUB求个和就好了\[ans=\sum_{i=1}^mf[n][i]\]

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define ll long long
#define mod 998244353
using namespace std;
string s;
ll fac[1000005],f[1005][1005],infac[1000005];
ll n,m;
ll qpow(ll a,ll b){
    ll ans=1ll,res=a;
    while(b){
        if(b&1) ans=(ans*res)%mod;
        res=(res*res)%mod;
        b>>=1;
    }
    return ans;
}
void pre(){
    ll nn=max(n,m);
//  nn=min(nn,1000000);
    fac[0]=1ll;
    for(ll i=1;i<=nn;i++) fac[i]=fac[i-1]*i*1ll%mod;
    infac[nn]=qpow(fac[nn],mod-2);

    for(ll i=nn-1;i>=0;i--) infac[i]=infac[i+1]*(i+1)*1ll%mod;
//  for(ll i=0;i<=nn;i++) printf("%lld ",infac[i]);
//  cout<<qpow(fac[nn],2)<<endl;
//  cout<<endl;
}
void work1(){
    if(n<=m) printf("1\n");
    else printf("0\n");
    return ;
}
void work2(){//LLC
    if(n<=m) printf("%lld",fac[m]*infac[m-n]%mod);
    else  printf("0\n");
//  else if(n==m) printf("")
}
void work3(){
    if(n<=m) printf("%lld",fac[m]*infac[n]%mod*infac[m-n]%mod);
    else printf("0\n");
}
void work4(){//LLB
    if(n<m){
        printf("0\n");
        return ;
    }
    ll ans=0;
    for(ll i=0;i<=m;i++){
        if(i%2==0) ans=(ans+fac[m]*infac[m-i]%mod*infac[i]%mod*qpow(m-i,n)%mod)%mod;
        else ans=(ans+mod-fac[m]*infac[m-i]%mod*infac[i]%mod*qpow(m-i,n)%mod)%mod;
    }
    printf("%lld\n",ans);
}
void work5(){//LUB
    if(n<m){
        printf("0\n");
        return ;
    }
    f[0][0]=1;
    //前 i个球放在 j个盒子里的方案数
    for(ll i=1ll;i<=n;i++)
      for(ll j=1ll;j<=m;j++)
        f[i][j]=(f[i-1][j-1]+j*f[i-1][j]%mod)%mod;
    printf("%lld\n",f[n][m]);
}
void work6(){//ULB
    if(n<m){
        printf("0\n");
        return ;
    }
    printf("%lld\n",fac[n-1]*infac[m-1]%mod*infac[n-m]%mod);
}
void work7(){//划分数 UUB
    if(n<m){
        printf("0\n");
        return ;
    }
    f[0][0]=1ll;
    for(ll i=1ll;i<=n;i++)
      for(ll j=1ll;j<=m;j++)
        f[i][j]=(f[i-1][j-1]+f[max(i-j,0ll)][j])%mod;
    printf("%lld",f[n][m]%mod);
}
void work8(){//LLA
    printf("%lld",qpow(m,n));
}
void work9(){
    f[0][0]=1;
    //前 i个球放在 j个盒子里的方案数
    for(ll i=1ll;i<=n;i++)
      for(ll j=1ll;j<=m;j++)
        f[i][j]=(f[i-1][j-1]+j*f[i-1][j]%mod)%mod;
    ll ans=0;
    for(ll i=1;i<=m;i++)
      ans=(ans+f[n][i])%mod;
    printf("%lld",ans);
}
void work10(){//ULA
    ll ans=0;
    for(ll i=0;i<=m;i++)
      ans=(ans+fac[m]*infac[i]%mod*infac[m-i]%mod*fac[n-1]%mod*infac[i-1]%mod*infac[n-i]%mod)%mod;
    printf("%lld",ans);
}
void work11(){//UUA
    f[0][0]=1;
    ll ans=0;
    for(ll i=1;i<=n;i++)
      for(ll j=1;j<=m;j++)
        f[i][j]=(f[i-1][j-1]+f[max(0ll,i-j)][j])%mod;
    for(ll i=1;i<=m;i++) ans=(ans+f[n][i])%mod;
    printf("%lld",ans);
}
int main(){
    cin>>s;
    scanf("%lld%lld",&n,&m);
    if(n<=1000000&&m<=1000000)pre();
//  cout<<s<<endl;
//    printf("%lld %lld\n",n,m);
    if(s=="LUC") work1();
    else if(s=="LLC") work2();
    else if(s=="UUC") work1();
    else if(s=="ULC") work3();
    else if(s=="LLB") work4();
    else if(s=="LUB") work5();
    else if(s=="ULB") work6();//
    else if(s=="UUB") work7();
    else if(s=="LLA") work8();
    else if(s=="LUA") work9();
    else if(s=="ULA") work10();//
    else if(s=="UUA") work11();
    return 0;
} 

原文地址:https://www.cnblogs.com/Vimin/p/11777437.html

时间: 2024-11-09 10:40:29

组合数学之TwelveFold Way的相关文章

【BZOJ2227】【ZJOI2011】看电影 [组合数学][质因数分解]

看电影 Time Limit: 10 Sec  Memory Limit: 259 MB[Submit][Status][Discuss] Description 到了难得的假期,小白班上组织大家去看电影.但由于假期里看电影的人太多,很难做到让全班看上同一场电影,最后大家在一个偏僻的小胡同里找到了一家电影院.但这家电影院分配座位的方式很特殊,具体方式如下: 1. 电影院的座位共有K个,并被标号为1…K,每个人买完票后会被随机指定一个座位,具体来说是从1…K中等可能的随机选取一个正整数,设其为L.

uva 1478 - Delta Wave(递推+大数+卡特兰数+组合数学)

题目链接:uva 1478 - Delta Wave 题目大意:对于每个位置来说,可以向上,水平,向下,坐标不能位负,每次上下移动最多为1, 给定n问说有多少种不同的图.结果对10100取模. 解题思路:因为最后都要落回y=0的位置,所以上升的次数和下降的次数是相同的,并且上升下降的关系满足出栈入栈的关系.即卡特兰数. 所以每次枚举i,表示有i个上升,i个下降,用组合数学枚举出位置,然后累加求和. C(2?in)?f(i)=C(2?i?2n)?f(i?1)?(n?2?i+1)?(n?2?i+2)

hdu2049(组合数学)

题意:每位新娘打扮得几乎一模一样,并盖上大大的红盖头随机坐成一排;然后,让各位新郎寻找自己的新娘.每人只准找一个,并且不允许多人找一个.最后,揭开盖头,如果找错了对象就要当众跪搓衣板...假设一共有N对新婚夫妇,其中有M个新郎找错了新娘,求发生这种情况一共有多少种可能. 解法:从N中选出M个C[n][m],然后乘上错排公式:f[n]=(n-1)*(f[n-1]+f[n-2]);f[0]=1;f[1]=0; 代码: /****************************************

BZOJ 1211: [HNOI2004]树的计数( 组合数学 )

知道prufer序列就能写...就是求个可重集的排列...先判掉奇怪的情况, 然后答案是(N-2)!/π(d[i]-1)! --------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; c

POJ3252 Round Numbers 组合数学||数位DP

这题目做了两个小时,调试的头都晕了... 题型是数位DP中很常见的,给一个区间[l,r]求区间[l,r]中的 符合题目要求的数的个数,本题求的 是 区间中 的数  它的二进制中0的个数大于等于1的个数的    这些数的个数,不好意思表达能力有点差...例如[1,4]答案是2, 因为 2的二进制是10,0的个数大于等于1的个数,4的二进制是100,0的个数大于1的个数,所以答案是两个 好了第一反应肯定是 设定一个函数 f(r) - f[l - 1]就是答案,那么显然这个函数f(r)的意思就是 1

[ACM] hihoCoder 1075 开锁魔法III (动态规划,组合数学)

描述 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜将会随机地选择 k 个盒子用魔法将它们打开.崔克茜想知道最后所有盒子都被打开的概率,你能帮助她回答这个问题吗? 输入 第一行一个整数 T (T ≤ 100)表示数据组数. 对于每组数据,第一行有两个整数 n 和 k (1?≤?n?≤?300,?0?≤?k?≤?n). 第二行有 n 个整数 ai,表示第 i 个盒子中,装有可以打开第 a

HDU - 4810 Wall Painting(组合数学)

Description Ms.Fang loves painting very much. She paints GFW(Great Funny Wall) every day. Every day before painting, she produces a wonderful color of pigments by mixing water and some bags of pigments. On the K-th day, she will select K specific bag

hdu4908 &amp; BestCoder Round #3 BestCoder Sequence(组合数学)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4908 BestCoder Sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 618    Accepted Submission(s): 214 Problem Description Mr Potato is a code

hdu 4869 Turn the pokers(递推&amp;组合数学&amp;逆元)

Turn the pokers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1279    Accepted Submission(s): 466 Problem Description During summer vacation,Alice stay at home for a long time, with nothing t