在WFU(不是大学简称)第二次比赛中做到了这道题。高中阶段参加过数竞的同学手算这样的题简直不能更轻松,只是套一个容斥原理公式就可以。而其实这个过程放到编程语言中来实现也没有那么的复杂,不过为了让计算机在限定的时间内完成计算需要进行一些对计算上的优化。模MOD的情况下计算组合数nCr只需要求出分子再乘以分母的逆元,考虑到模的是1e9+7本身就是一个质数,根据费马小定理a^(MOD-2)即是a在模MOD意义下的逆元。求逆元的时候为了节约计算时间可以采用快速幂。计算过程就是容斥原理,就没有什么好说的了。
参考代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD=(int)1e9+;
ll f[],fact[];
ll fast_exp(ll base,ll exp,ll mod)
{
ll res=;
while(exp)
{
if(exp&)
res=res*base%mod;
base=base*base%mod;
exp>>=;
}
return res;
}
ll inverse_mod(ll x,ll mod)
{
return fast_exp(x,mod-,mod);
}
ll nCr(ll n,ll r)
{
if(n<r)
return ;
r=min(r,n-r);
ll ret=;
for(ll x=n;x>n-r;x--)
{
ret=(ret*(x%MOD))%MOD;
}
ret=(ret*inverse_mod(fact[r],MOD))%MOD;
return ret;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n,i,j,N,cnt;
ll s,temp,ans=;
fact[]=;
for(i=;i<;i++)
fact[i]=(fact[i-]*i)%MOD;
cin>>n>>s;
for(i=;i<n;i++)
cin>>f[i];
N=<<n;
for(i=;i<N;i++)
{
temp=,cnt=;
for(j=;j<n;j++)
{
if(i&(<<j))
{
temp+=(f[j]+);cnt++;
}
}
if(temp>s)
continue;
ll x=nCr(s-temp+n-,n-);
if(cnt%!=)
x*=(-);
ans=(ans+x+MOD)%MOD;
}
cout<<ans<<"\n";
return ;
}
果然计算机和数学联系还是十分密切,当初搞数竞的时候觉得那些奇技淫巧恐怕难觅用武之地,结果现在才发现这些原来在编程中有很大的应用……眼前又是新的挑战,无论如何都不想再经历像高三那一年一样的绝望了吧……那么,加油吧,就像曾经一样,付出你的全部热情。不论你还相不相信你还可以成功,这都是可能使你回到巅峰的唯一途径了。让苦难成为力量。