BUAA 413 梦(组合)

题目链接:http://acm.buaa.edu.cn/problem/413/

题意:将m写成n个非负整数的和的形式。将所有写法中的正数相乘,输出该值。

思路:对于每个数i,可以被放在任意一个位置。枚举一个数 i(1<=i<= m),我们要计算他会被使用多少次?除了i外,剩下的数和是m-i,分成n-1个数。于是就被转化成了很m-i个相同的球放进n-1个不同的盒子,盒子可以空,有多少种方案。公式是C[n-1+m-i-1][n-2]。再乘以n(i可以放在任意一个位置),变成 n*C[n-1+m-i-1][n-2] 就是i 这个数字会被用多少次。由费马小定理a^(p-1) ≡ 1 (mod p)可得:a^b%p=a^(b%(p-1))%p。

#include <iostream>

#include <cstdio>

#include <string.h>

#include <algorithm>

#include <cmath>

#include <vector>

#include <queue>

#include <set>

#include <string>



#define max(x,y) ((x)>(y)?(x):(y))

#define min(x,y) ((x)<(y)?(x):(y))

#define abs(x) ((x)>=0?(x):-(x))

#define i64 long long

#define u32 unsigned int

#define u64 unsigned long long

#define clr(x,y) memset(x,y,sizeof(x))

#define pb(x) push_back(x)

#define SZ(x) x.size()

#define PI acos(-1.0)

#define sqr(x) ((x)*(x))

using namespace std;



const i64 mod=1000000007;

i64 c[2005][2005];

int n,m,C;



void init()

{

    int i,j;

    for(i=0;i<=2000;i++)

    {

        c[i][0]=c[i][i]=1;

        for(j=1;j<i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%(mod-1);

    }

}



i64 POW(i64 x,i64 y)

{

    i64 ans=1;

    while(y)

    {

        if(y&1) ans=ans*x%mod;

        x=x*x%mod;

        y>>=1;

    }

    return ans;

}



i64 cal()

{

    if(n==1) return m;

    i64 ans=1,i,j;

    for(i=2;i<=m;i++)

    {

        j=n*c[m-i+n-1-1][n-2]%(mod-1)%mod;

        ans=ans*POW(i,j)%mod;

    }

    return ans;

}



int main()

{

    init();

    for(scanf("%d",&C);C--;)

    {

        scanf("%d%d",&n,&m);

        printf("%lld\n",cal());

    }

    return 0;

}

  

 

你可能感兴趣的:(413)