hdu 6143 (2017多校联赛8-11)

来源:互联网 发布:c语言中结构体的使用 编辑:程序博客网 时间:2024/05/22 06:45

Killer Names

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 256    Accepted Submission(s): 133

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.>> — WookieepediaDarth 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 (T10), denoting the number of test cases. Each test case contains two integers n and m (1n,m2000).
 

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

         一场比赛我就做了这一题,最后连T了好多次也没找到问题,最后看了一位仁兄的才知道,打表不能多打啊,多打就T了大哭

      这题最关键的地方在于如何用r个字符(必须全用上)搞出长度为n的名字。

      先说大体过程:先在m个字符里取r个,作为长度为n的姓的组成元素,为了避免重复,我们要求选出的元素必须至少出现一次,所有可能记为sum1。然后在剩下的m-r个字符里取k个,作为长度为n的名的组成元素,同样为了避免重复,我们要求选出的元素必须至少出现一次,所有可能记为sum2。那么,总的个数就是对所有的 sum1*sum2求和。

      下面讲关键的地方,要用到去重的思想:r个字符组成n长的字符串个数为d(r),不算重复,共有r^n个,重复的部分应该分成r-1部分来看:在r个里面选r-1个字符组成的字符串个数,C(r,r-1)*d(r-1)、r个里面选r-2个字符组成的字符串个数,C(r,r-2)*d(r-2)、r个里面选r-3个字符组成的字符串个数,C(r,r-3)*d(r-3)、……、r个里面选1个字符组成的字符串个数,C(r,1)*d(1)   (PS:这r-1部分都是独立的)。

      由此可以得到d(r)=r^n-C(r,r-1)*d(r-1)-C(r,r-2)*d(r-2)-C(r,r-3)*d(r-3)-……-C(r,1)*d(1);

      r^n要用快速幂,组合数要打表(大哭),否则就超时。

下面是AC代码:

#include<cstdio>#define MOD 1000000007using namespace std;long long C[2010][2010];long long d[2010];long long cal[2010];typedef long long ll;ll mod_pow(ll x,ll n,ll mod){//快速幂板子    ll res =1;    while (n>0){        if (n & 1)res = res * x % mod;        x=x*x%mod;        n>>=1;    }    return res;}void get_C(int maxn ){//组合数板子 C[0][0] = 1;    for(int i=1;i<=maxn;i++)    {        C[i][0] = 1;        for(int j=1;j<=i;j++)            C[i][j] = (C[i-1][j]+C[i-1][j-1])%MOD;    }}int main(){    get_C(2001);//一开始用的是2010,咋跑都是T,好气啊    ll n,m,t;    scanf("%lld", &t);    while (t--){        scanf("%lld%lld", &n,&m);        d[1]=1;        for (ll i=2;i<=n;i++){//关键点            d[i]=mod_pow(i,n,MOD);            for (ll j=1;j<i;j++){                d[i]-=C[i][j]*d[j]%MOD;                d[i]=(d[i]+MOD)%MOD;//因为是减,所以要加个MOD,防止负数            }        }        ll sum1=0,sum2=0,sum=0;        for (ll r=1;r<=n&&r<m;r++){            sum1=C[m][r]*d[r]%MOD;            for (ll k=1;k<=n&&k<=m-r;k++){                sum2=C[m-r][k]*d[k]%MOD;                sum=(sum+sum1*sum2)%MOD;            }        }        printf("%lld\n", sum);    }    return 0;}


原创粉丝点击