题意:n个区间,每个区间可以取区间中的任意一个数,问取的数和为m的方案数。
题解:先看codeforce上的451E的区间都是从0开始,所以我们先看code上的题。
我们可以把m分为n份。那么利用隔板法,总的取法为C(n+m-1,n-1)。
因为这样分的话,肯定有一些区间取的数多于那个区间的最大值,我们把这一部分减去就是我们要求的答案,
怎么求多的那一部分呢,利用容斥原理,他超出的最小值为1,我们让sum-a[i]-1,表示分给他a[i]+1个然后这部分肯定超出限制,然后剩下的值也是最大的,最后我们把剩下的再分给n个即可,因为有重复的情况,我们利用容斥原理,我们可以加上超出的区间为0个的情况,然后减去1个的情况,加上2个的情况。。。
以下是code的代码
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <algorithm>
typedef long long LL;
using namespace std;
LL p=1e9+7;
LL exp_mod(LL a, LL b, LL p) {
LL res = 1;
while(b != 0) {
if(b&1) res = (res * a) % p;
a = (a*a) % p;
b >>= 1;
}
return res;
}
LL Comb(LL a, LL b, LL p) {
if(a < b) return 0;
if(a == b) return 1;
if(b > a - b) b = a - b;
LL ans = 1, ca = 1, cb = 1;
for(LL i = 0; i < b; ++i) {
ca = (ca * (a - i))%p;
cb = (cb * (b - i))%p;
}
ans = (ca*exp_mod(cb, p - 2, p)) % p;
return ans;
}
LL Lucas(LL n, LL m) {
LL ans = 1;
while(n&&m&&ans) {
ans = (ans*Comb(n%p, m%p, p)) % p;
n /= p;
m /= p;
}
return ans;
}
LL a[123];
int main()
{
LL n, m;
scanf("%lld%lld",&n,&m);
for(LL i=0;i<n;i++)
{
scanf("%lld",&a[i]);
}
LL ans=0;
for(LL i=0;i<(1<<n);i++)
{
LL sum=m;LL flag=1;
for(LL j=0;j<n;j++)
{
if((1<<j)&i)
{
sum-=a[j];sum--;
flag*=-1;
}
}
if(sum<0) continue;
else
{
LL ans1=Lucas(sum+n-1,n-1);
ans+=flag*ans1;
ans%=p;
}
//printf("%lld\n",ans);
}
while(ans<0)
ans+=p;
printf("%lld\n",ans);
return 0;
}
Light上的是code上的变形,我们可以让区间[l,r]变为区间[0,r-l],同时m-l即可,注意mod值为1e8+7,而codeforce上mod值位1e9+7下面是Light的代码。
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <algorithm>
typedef long long LL;
using namespace std;
LL p=1e8+7;
LL exp_mod(LL a, LL b, LL p) {
LL res = 1;
while(b != 0) {
if(b&1) res = (res * a) % p;
a = (a*a) % p;
b >>= 1;
}
return res;
}
LL Comb(LL a, LL b, LL p) {
if(a < b) return 0;
if(a == b) return 1;
if(b > a - b) b = a - b;
LL ans = 1, ca = 1, cb = 1;
for(LL i = 0; i < b; ++i) {
ca = (ca * (a - i))%p;
cb = (cb * (b - i))%p;
}
ans = (ca*exp_mod(cb, p - 2, p)) % p;
return ans;
}
LL Lucas(LL n, LL m) {
LL ans = 1;
while(n&&m&&ans) {
ans = (ans*Comb(n%p, m%p, p)) % p;
n /= p;
m /= p;
}
return ans;
}
LL a[123];
int main()
{
LL n, m,cas=1;int t;scanf("%d",&t);
while(t--)
{
scanf("%lld%lld",&n,&m);
for(LL i=0;i<n;i++)
{
LL l,r;
scanf("%lld%lld",&l,&r);
a[i]=r-l;
m-=l;
}
LL ans=0;
for(LL i=0;i<(1<<n);i++)
{
LL sum=m;LL flag=1;
for(LL j=0;j<n;j++)
{
if((1<<j)&i)
{
sum-=a[j];sum--;
flag*=-1;
}
}
if(sum<0) continue;
else
{
LL ans1=Lucas(sum+n-1,n-1);
ans+=flag*ans1;
ans%=p;
}
//printf("%lld\n",ans);
}
while(ans<0)
ans+=p;
printf("Case %lld: %lld\n",cas++,ans);
}
return 0;
}