bzoj4710: [Jsoi2011]分特产

来源:互联网 发布:百度软件开放平台 编辑:程序博客网 时间:2024/04/28 06:03

感想

一开始我想的方向错了,然后一直没有弄出来。。最后只能弄到一个每个人分到的东西,1,2和2,1视作两种方案。。就是用一下部分一样公式和一大堆公式搞一下,反正就GG了
感觉这题展现出我的容斥思想与组合数学的思维还不够啊,看来我的数学还要多多提升

顺便,终于突破非权限400题了 lalal~

题解

看了题解才回过头来。。
首先我们对于每一样物品,我们都可以送给别人,这个方案是可以算的
要是这个物品有ai样,那么就是说要求x1+x2+x3+…..xn=ai,x有多少种非负整数解。。
这个的话插板法可以弄。。我前一天才在书上学会的,下面说说证明(我还想了很久,看书会的):
就是说我们可以看做现在有ai+n-1个格子,任意选n-1个当板,然后剩下填1就是答案了
所以答案是C(n-1,ai+n-1)
然而这还不行因为他是非负整数解
所以x是可能等于0的,但不是我们想要的结果。。
于是考虑容斥原理
答案应该为至少0个盒子为空的-至少1个盒子为空的+至少2个盒子为空的-…至少n个盒子为空的
然后就强制要求一下有多少个盒子是不可以用的

#include<cstdio>#include<cstring>typedef long long LL;const LL N=2005;const LL MOD=1e9+7;LL n,m;LL a[N];LL c[N][N];int main(){    LL ans=0;    for (LL i=0;i<=2000;++i) c[i][0]=1;    for (LL i=1;i<=2000;++i)        for (LL j=1;j<=2000;++j)            c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD;    scanf("%lld%lld",&n,&m);    for (LL u=1;u<=m;u++)   scanf("%lld",&a[u]);    LL f=1;    for (LL u=0;u<=n;u++)//有多少个箱子空着     {        LL now=f;        for (LL i=1;i<=m;i++)            now=now*c[a[i]+n-u-1][n-u-1]%MOD;        ans=(ans+now*c[n][u]%MOD)%MOD;        f*=-1;    }    ans=(ans+MOD)%MOD;    printf("%lld\n",ans);    return 0;}
原创粉丝点击