列表

详情


NC20189. [JSOI2011]分特产

描述

JYY 带队参加了若干场ACM/ICPC 比赛,带回了许多土特产,要分给实验室的同学们。
JYY 想知道,把这些特产分给N 个同学,一共有多少种不同的分法?
当然,JYY 不希望任何一个同学因为没有拿到特产而感到失落,所以每个同学都必须至少分得一个特产。
例如,JYY 带来了2 袋麻花和1 袋包子,分给A 和B 两位同学,那么共有4 种不同的分配方法: 
A:麻花,B:麻花、包子 
A:麻花、麻花,B:包子
A:包子,B:麻花、麻花
A:麻花、包子,B:麻花

输入描述

输入数据第一行是同学的数量N和特产的数量M。
第二行包含M个整数,表示每一种特产的数量。
N, M不超过1000,每一种特产的数量不超过1000

输出描述

输出一行,不同分配方案的总数。由于输出结果可能非常巨大,你只需要输出最终结果MOD 1,000,000,007的数值就可以了。

示例1

输入:

5 4
1 3 3 5

输出:

384835

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 36ms, 内存消耗: 31896K, 提交时间: 2022-10-18 20:13:47

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=1e9+7;

ll C[2005][2005],f[2005];
int n,m;
int a[2005];

void getC()
{
    for (int i=0; i<=2000; ++i)
    {
        for (int j=0; j<=i; ++j)
        {
            if (j==0 || j==i) C[i][j]=1;
            else C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
        }
    }
}

int main()
{
    memset(C,0,sizeof(C));
    cin>>n>>m;
    for (int i=1; i<=m; ++i) cin>>a[i];
    getC();
    for (int i=0; i<n; ++i)
    {
        f[i]=C[n][i];
        ll sum=1;
        for (int j=1; j<=m; ++j) sum=(sum*C[a[j]+n-i-1][n-i-1])%mod;
        f[i]=f[i]*sum%mod;
    }
    ll ans=0;
    for (int i=0; i<n; ++i)
        if (i%2==0) ans=(ans+f[i])%mod;
        else ans=(ans-f[i]+mod)%mod;
    cout<<ans;
    return 0;
}

C++(clang++11) 解法, 执行用时: 18ms, 内存消耗: 14332K, 提交时间: 2020-10-29 15:08:44

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=2e3+5,mod=1e9+7;
int n,m,a[N],c[N][N],ans;
void add(int &x,int y){x=(x+y>=mod)?x+y-mod:x+y;}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)scanf("%d",&a[i]);
	for(int i=0;i<N;i++)c[i][0]=1;
	for(int i=1;i<N;i++)for(int j=1;j<=i;j++)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
	for(int i=0,sgn=1,res;i<n;i++,sgn=-sgn){
		res=c[n][i];
		for(int j=1;j<=m;j++)res=(LL)res*c[a[j]+n-i-1][n-i-1]%mod;
		add(ans,(res*sgn+mod)%mod);
	}
	printf("%d\n",ans);
	return 0;
}

上一题