这类有数量限制的题目都是上界减去下界,转化为只有上界的,然后嘛对每种状态进行容斥计算,不过这里要计算非法排列,不进行正面计算
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 2222;
const int mod = 100000007;
ll f[1000090];
int L[55],R[55];
int k,n;
ll ans=0;
inline ll POW(ll a,ll b,int mod)
{
ll res=1,t=a;
while(b)
{
if(b&1) res=res*t%mod;
t=t*t%mod;
b>>=1;
}
return res;
}
inline ll cal(int n,int m)
{
ll a=POW(f[n-m],mod-2,mod)*POW(f[m],mod-2,mod)%mod;
return a*f[n]%mod;
}
inline void gao(int x,int cnt,int remain)
{
if(x==0)
{
if(cnt&1)
{
ans-=cal(remain+k-1,k-1);
}
else
{
ans+=cal(remain+k-1,k-1);
}
}
else
{
gao(x-1,cnt,remain);
if(remain>R[x])
gao(x-1,cnt+1,remain-R[x]-1);
}
}
void init()
{
f[0]=1;
for(int i=1;i<=1000080;++i)
{
f[i]=f[i-1]*i;
if(f[i]>=mod)
f[i]%=mod;
}
}
int main() {
init();
int T,cas,i;
scanf("%d",&T);
for(cas=1;cas<=T;++cas)
{
scanf("%d%d",&k,&n);
for(i=1;i<=k;++i)
{
scanf("%d%d",L+i,R+i);
}
for(i=1;i<=k;++i)
{
n-=L[i];
R[i]-=L[i];
}
ans=0;
if(n>=0)
gao(k,0,n);
ans=(ans+1ll*mod*mod)%mod;
printf("Case %d: %lld\n",cas,ans);
}
return 0;
}