传送门冲冲冲

注意一点,下面甲乙使用的数组名 L , R L,R L,R相同(我比较懒),区别在于上下标的不同

设甲方 ∑ i = 1 k 1 R i − x i \sum\limits_{i=1}^{k_1}R_i-x_i i=1k1Rixi

设乙方 ∑ i = 1 k 2 L i + y i \sum\limits_{i=1}^{k_2}L_i+y_i i=1k2Li+yi

易得 x i ∈ [ 0 , R i − L i ] , y i ∈ [ 0 , R i − L i ] x_i\in[0,R_i-L_i],y_i\in[0,R_i-L_i] xi[0,RiLi],yi[0,RiLi]

若甲大于乙

∑ i = 1 k 1 ( R i − x i ) > ∑ i = 1 k 2 ( L i + y i ) \sum\limits_{i=1}^{k_1}(R_i-x_i)>\sum\limits_{i=1}^{k_2}(L_i+y_i) i=1k1(Rixi)>i=1k2(Li+yi)

满足 ∑ i = 1 k 1 x i + ∑ i = 1 k 2 y i < s u m \sum\limits_{i=1}^{k_1}x_i+\sum\limits_{i=1}^{k_2}y_i<sum i=1k1xi+i=1k2yi<sum

其中 s u m sum sum即为甲方的 R R R的和加上乙方 L L L的和

变形一下得到

∑ i = 1 k 1 x i + ∑ i = 1 k 2 y i + k = s u m − 1 \sum\limits_{i=1}^{k_1}x_i+\sum\limits_{i=1}^{k_2}y_i+k=sum-1 i=1k1xi+i=1k2yi+k=sum1

为了方便,下面令令 m = k 1 + k 2 m=k_1+k_2 m=k1+k2

那么就是 s u m − 1 sum-1 sum1个数字放在 m + 1 m+1 m+1个未知数里,求方案数

使用隔板法, s u m − 1 sum-1 sum1个数字排列成一排有 s u m − 2 sum-2 sum2个空隙

使用 m m m个隔板插入这些间隙可以分成 m + 1 m+1 m+1个组

所以这样方案数是 C s u m − 2 m C_{sum-2}^{m} Csum2m

但是每个组内部可以为空,所以我们默认多出 m + 1 m+1 m+1个球先放在每个组

所以这样方案数是 C s u m − 2 + m + 1 m = C s u m + m − 1 m C_{sum-2+m+1}^{m}=C_{sum+m-1}^{m} Csum2+m+1m=Csum+m1m

接 下 来 还 需 要 容 斥 原 理 \color{Red}接下来还需要容斥原理

d f s dfs dfs搜索哪几个组超过了自身的容量 R i − L i R_i-L_i RiLi,奇加偶减

那么平局有什么变化呢?

满足 ∑ i = 1 k 1 ( R i − x i ) = ∑ i = 1 k 2 ( L i + y i ) \sum\limits_{i=1}^{k_1}(R_i-x_i)=\sum\limits_{i=1}^{k_2}(L_i+y_i) i=1k1(Rixi)=i=1k2(Li+yi)

即为 ∑ i = 1 k 1 x i + ∑ i = 1 k 2 y i = s u m \sum\limits_{i=1}^{k_1}x_i+\sum\limits_{i=1}^{k_2}y_i=sum i=1k1xi+i=1k2yi=sum

就是 s u m sum sum个数字放在 m m m个未知数里去

s u m sum sum个数排成一排有 s u m − 1 sum-1 sum1个间隙

m − 1 m-1 m1个隔板插进去分割成 m m m个组别

又由于每组不为空,答案是 C s u m − 1 + m m − 1 C_{sum-1+m}^{m-1} Csum1+mm1

同样容斥

#include <iostream>
#include <algorithm>
using namespace std;
#define int long long
const int maxn=29;
const int mod=1e9+7;
int L[maxn],R[maxn],mu,ans1,ans2,ans3,k1,k2,m,sumn;
int quick_pow(int x,int n)
{
	int ans=1;
	while( n )
	{
		if( n&1 )	ans=ans*x%mod;
		n>>=1; x = x*x%mod;
	}	return ans;
}
void inv(int &x){ x = x*quick_pow(mu,mod-2)%mod; x = (x+mod)%mod; }
int C(int n,int m)
{
	if( n<m )	return 0;
	int res=1;
	for(int i=n-m+1;i<=n;i++)	res=res*i%mod;
	for(int i=1;i<=m;i++)	res=res*quick_pow(i,mod-2)%mod;
	return res;
}
void dfs(int num,int f,int x)
{
	if( num==k1+k2+1 )
	{
		ans1 = ( ans1+f*C(sumn-x+(m-1),m)%mod )%mod; 
		ans2 = ( ans2+f*C(sumn-x+(m-1),m-1)%mod )%mod;
		return;
	}
	dfs(num+1,f,x);
	dfs(num+1,-f,x+R[num]-L[num]+1);
}
signed main()
{
	int T; cin >> T;
	while( T-- )
	{
		sumn=ans1=ans2=ans3=0,mu=1;
		cin >> k1;
		for(int i=1;i<=k1;i++)
		{
			cin >> L[i] >> R[i];
			sumn += R[i];
		}
		cin >> k2;
		for(int i=k1+1;i<=k1+k2;i++)
		{
			cin >> L[i] >> R[i];
			sumn -= L[i];
		}
		m = k1+k2;
		for(int i=1;i<=m;i++)	mu = mu*( R[i]-L[i]+1 )%mod;
		dfs(1,1,0);
		ans3 = ((mu-ans1-ans2)%mod+mod)%mod;
		inv(ans1); 
		inv(ans2);
		inv(ans3);
		printf("%lld %lld %lld\n",ans1,ans2,ans3);
	}
}