codeforces 451E Devu and Flowers(容斥原理,Lucas,二进制另一种模板,隔板法)

 Devu and Flowers

time limit per test4 seconds

memory limit per test256 megabytes
 


 

Devu wants to decorate his garden with flowers. He has purchased n boxes, where the i-th box contains fi flowers. All flowers in a single box are of the same color (hence they are indistinguishable). Also, no two boxes have flowers of the same color.

Now Devu wants to select exactly s flowers from the boxes to decorate his garden. Devu would like to know, in how many different ways can he select the flowers from each box? Since this number may be very large, he asks you to find the number modulo (109 + 7).

Devu considers two ways different if there is at least one box from which different number of flowers are selected in these two ways.

Input

The first line of input contains two space-separated integers n and s (1 ≤ n ≤ 20, 0 ≤ s ≤ 1014).

The second line contains n space-separated integers f1, f2, ... fn (0 ≤ fi ≤ 1012).

Output

Output a single integer — the number of ways in which Devu can select the flowers modulo (109 + 7).

Examples

Input

2 3
1 3

Output

2

Input

2 4
2 2

Output

1

Input

3 5
1 3 2

Output

3

Note

Sample 1. There are two ways of selecting 3 flowers: {1, 2} and {0, 3}.

Sample 2. There is only one way of selecting 4 flowers: {2, 2}.

Sample 3. There are three ways of selecting 5 flowers: {1, 2, 2}, {0, 3, 2}, and {1, 3, 1}.


 

题目链接:http://codeforces.com/problemset/problem/451/E


算法分析:

题意:

n个盒子,第i个里有f[i]朵花,同盒的花都同色,每个盒子的花色都不同,求选s朵的方案

分析:

首先sum朵花放到n个盒子里允许盒子为空的方案数通过隔板法是C(sum + n - 1, n - 1)

 

但是有f[i]限制的情况。我们可以假装取超了,假装已经在第i个盒子取了f[i]+1个球,把总球数减去(f[i]+1) (因为允许箱子为空一开始要人为加入一个球,所以+1),用这个总球数可以用C(sum-f[i]-1+s-1,n-1)算出取超了的情况的种类数。

然后可能有0个盒子取超、1个盒子盒子取超、2个盒子取超……等等好多情况,这些情况还有互相重复的,这就要用到容斥原理。

ans=0个超的情况数 - 各种1个盒子超的情况数 +各种2盒子个超的情况数 - 各种3个盒子超的情况数……

如果按照以前的思路:

ans=总的-(各种1个盒子超的情况数 +各种2盒子个超的情况数 - 各种3个盒子超的情况数…)

其实思维是一样的

Lucas定理直接套的模板,但那个竟然超时了。换了一个。

 

#include<cstdio>  
#include<cstring>  
#include<cstdlib>  
#include<cctype>  
#include<cmath>  
#include<iostream>  
#include<sstream>  
#include<iterator>  
#include<algorithm>  
#include<string>  
#include<vector>  
#include<set>  
#include<map>  
#include<stack>  
#include<deque>  
#include<queue>
using namespace std;
typedef long long ll;
long long sum=0,n,m;
const ll mod=1e9+7;
ll f[25];
ll qpow(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1)ans=(ans*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return ans;
}
ll getc(ll a,ll b)
{
	if(a<b)return 0;
	if(b>a-b)b=a-b;
	ll s1=1,s2=1;
	for(ll i=0;i<b;i++)
	{
		s1=s1*(a-i)%mod;
		s2=s2*(i+1)%mod;
	}
	return s1*qpow(s2,mod-2)%mod;
}
ll lucas(ll n,ll k)
{
    if(k==0)return 1;
    return getc(n%mod,k%mod)*lucas(n/mod,k/mod)%mod;
}

ll solve()
{
    ll ans=0;
    for(int i=0;i<(1<<n);i++) //第二种二进制模板,这里是从0开始的
    {
        ll cnt=0,sum=m;
        for(int j=0;j<n;j++)
        {
            if(i&(1<<j))
            {
                sum-=f[j]+1;
              cnt++;
            }
        }
        if(sum<0)continue;
        if(cnt&1) ans-=lucas(sum+n-1,n-1);
		  else    ans+=lucas(sum+n-1,n-1);
        ans%=mod;
    }    return (ans+mod)%mod;
}
 
int main()
{

   scanf("%lld%lld",&n,&m);
    
    	    for(int i=0;i<n;i++)
    	    	scanf("%lld",&f[i]);
          
            printf("%lld\n",solve());
           
    
    return 0;
} 

 

猜你喜欢

转载自blog.csdn.net/sdz20172133/article/details/81713438
今日推荐