HDU 6143 Killer Names 组合数+(容斥/第二类Stirling数)

来源:互联网 发布:伊斯兰教 知乎 编辑:程序博客网 时间:2024/04/29 16:32

Problem Description

Galen Marek, codenamed Starkiller, was a male Human apprentice of the Sith Lord Darth Vader. A powerful Force-user who lived during the era of the Galactic Empire, Marek originated from the Wookiee home planet of Kashyyyk as the sole offspring of two Jedi Knights—Mallie and Kento Marek—who deserted the Jedi Order during the Clone Wars. Following the death of his mother, the young Marek’s father was killed in battle by Darth Vader. Though only a child, Marek possessed an exceptionally strong connection to the Force that the Dark Lord of the Sith sought to exploit.

When Marek died in 2 BBY, shortly after the formation of the Alliance, Vader endeavored to recreate his disciple by utilizing the cloning technologies of the planet Kamino. The accelerated cloning process—an enhanced version of the Kaminoan method which allowed for a rapid growth rate within its subjects—was initially imperfect and many clones were too unstable to take Marek’s place as the Dark Lord’s new apprentice. After months of failure, one particular clone impressed Vader enough for him to hope that this version might become the first success. But as with the others, he inherited Marek’s power and skills at the cost of receiving his emotions as well, a side effect of memory flashes used in the training process.

— Wookieepedia

Darth Vader is finally able to stably clone the most powerful soilder in the galaxy: the Starkiller. It is the time of the final strike to destroy the Jedi remnants hidden in every corner of the galaxy.

However, as the clone army is growing, giving them names becomes a trouble. A clone of Starkiller will be given a two-word name, a first name and a last name. Both the first name and the last name have exactly n characters, while each character is chosen from an alphabet of size m. It appears that there are m2n possible names to be used.

Though the clone process succeeded, the moods of Starkiller clones seem not quite stable. Once an unsatisfactory name is given, a clone will become unstable and will try to fight against his own master. A name is safe if and only if no character appears in both the first name and the last name.

Since no two clones can share a name, Darth Vader would like to know the maximum number of clones he is able to create.

Input

The First line of the input contains an integer T (T≤10), denoting the number of test cases.

Each test case contains two integers n and m (1≤n,m≤2000).

Output

For each test case, output one line containing the maximum number of clones Vader can create.

Output the answer mod 109+7

Sample Input

23 22 3

Sample Output

2 18

Source

2017 Multi-University Training Contest - Team 8

题目大意

有m个不同的字母然后组成两个长度为n的字符串,要求两个串中不能有相同的字符。

解题思路

容斥思想: HDU 6143 Killer Names (容斥)
第二类斯特林数是将p个元素划分到k个非空的没有区别的盒子中的划分种类数,记为s(p,k)。
所以根据题意,我们可以理解为将n个小球分到x个颜料盒中进行染色,若不区分颜料盒,即为s(n,x),但是x个颜料盒是不同的,所以用x中颜色对n个小球进行染色的种类数为 s(n,x)*x!。即为容斥思想中提到的F(n,x)。

小总结:

第二类Stirling数

S(p,k)代表将p个元素划分到k个非空的没有区别的盒子中的划分种类数
递推公式:
S(p,p)=1(p>=0)
S(p,0)=0(p>=1)
S(p,k)=k*S(p-1,k)+S(p-1,k-1)(1<=k<=p-1)
理解:第p个物品,可以自己单独构成一个集合,则另外p-1个物品构成其余的k-1个集合,此时种类数为s(p-1,k-1);也可以由p-1个物品构成k个集合,然后第p个物品可以放入k个集合的任意一个集合中,即k*s(p-1,k)种。

void init(){    memset(st,0,sizeof(st));    st[1][1]=1;    for(int i=2;i<=maxn-1;i++)        for(int j=1;j<=i;j++)    {        st[i][j]=st[i-1][j-1]+j*st[i-1][j];    }}

第一类Stirling数

S(p,k) 代表将p个元素排成k个非空循环排列的种类数。
递推公式:
S(p,p)=1(p>=0)
S(p,0)=0(p>=1)
S(p,k)=(p-1)*S(p-1,k)+S(p-1,k-1)(1<=k<=p-1)
理解:第p个物品可以单独构成一个非空循环排列,则其余的p-1个物品构成剩余的k-1个非空循环排列,此时种类数为s(p-1,k-1);也可以其中p-1个物品构成k个非空循环排列,然后第k个物品可以放在p-1个物品任意一个的左边,有(p-1)*s(p-1,k-1)种。

void init(){    memset(st,0,sizeof(st));    st[1][1]=1;    for(int i=2;i<=maxn-1;i++)        for(int j=1;j<=i;j++)    {        st[i][j]=st[i-1][j-1]+(i-1)*st[i-1][j];    }}

代码实现

第二类Stirling数

#include<iostream>#include<cstdio>#include<cstring>using namespace std;#define ll long long#define maxn 2005#define mod 1000000007ll num[maxn];ll c[maxn][maxn];    //组合数打表ll st[maxn][maxn];    //存放要求的Stirling数void init1(){    num[0]=1;    for(int i=1;i<maxn;i++)        num[i]=num[i-1]*i%mod;}void init2()//预处理{    memset(st,0,sizeof(st));    st[1][1]=1;    for(int i=2;i<=maxn-1;i++)        for(int j=1;j<=i;j++)    {        st[i][j]=(st[i-1][j-1]+j*st[i-1][j])%mod;    }}void init3(){    c[0][0]=1;    for(int i=1; i<maxn; i++)        for(int j=0; j<=i; j++)            c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;}int main(){    init1();    init2();    init3();    int T;    scanf("%d",&T);    while(T--)    {        int n,m;        ll ans=0;        scanf("%d %d",&n,&m);        for(int i=1; i<m; i++)            for(int j=i; j<=m-i; j++)            {                ll aa=(c[m][i]*st[n][i]%mod)*num[i]%mod;                ll bb=(c[m-i][j]*st[n][j]%mod)*num[j]%mod;                ll cnt = (aa*bb)%mod;                if(i!=j) cnt = (cnt+cnt)%mod;                ans=(cnt+ans)%mod;            }        printf("%lld\n",ans);    }    return 0;}
原创粉丝点击