LightOJ 1124 Cricket Ranking(多重组合数学)

题目链接:LightOJ 1124 Cricket Ranking

题目大意

有k个区间每个区间选出来一个数,使得k个数的和为n,问有多少种方案。

解题思路

这是一个多重集合的排列组合问题
设 多 重 集 合 S = n 1 ∗ a 1 , n 2 ∗ a 2 , . . . , n k ∗ a k , n = n 1 + n 2 + . . . + n k 设多重集合 S = { n_1 * a_1, n_2 * a_2, ..., n_k * a_k },n = n_1 + n_2 + ... + n_k S=n1a1,n2a2,...,nkak,n=n1+n2+...+nk

即 集 合 S 中 含 有 n 1 个 元 素 a 1 , n 2 个 元 素 a 2 , . . . , n k 个 元 素 a k , n i 被 称 为 元 素 a i 的 重 数 , k 成 为 多 重 集 合 的 类 别 数 即集合 S 中含有n_1个元素a_1, n_2个元素a_2,...,n_k个元素a_k,n_i被称为元素a_i的重数,k成为多重集合的类别数 Sn1a1n2a2...nkakniaik

在 S 中 任 选 r 个 元 素 的 排 列 称 为 S 的 r 排 列 , 当 r = n 时 , 有 公 式 P ( n ; n 1 ∗ a 1 , n 2 ∗ a 2 , . . . , n k ∗ a k ) = n ! / ( n 1 ! ∗ n 2 ! ∗ . . . ∗ n k ! ) 在 S 中任选 r 个元素的排列称为S的r排列,当r = n时,有公式 P(n; n_1*a_1, n_2*a_2, ..., n_k*a_k) = n! / (n_1! * n_2! * ...* n_k!) SrSrr=nP(n;n1a1,n2a2,...,nkak)=n!/(n1!n2!...nk!)

在 S 中 任 选 r 个 元 素 的 组 合 称 为 S 的 r 组 合 , 当 r < = 任 意 n i 时 , 有 公 式 C ( n ; n 1 ∗ a 1 , n 2 ∗ a 2 , . . . , n k ∗ a k ) = C ( k + r − 1 , r ) 在 S 中任选 r 个元素的组合称为S的r组合,当r<=任意n_i时,有公式 C(n; n_1*a_1, n_2*a_2, ..., n_k*a_k) = C(k+r-1, r) SrSrr<=niC(n;n1a1,n2a2,...,nkak)=C(k+r1,r)
多重集合的排列和组合问题
大佬的本题题解

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=100000007;

ll ve[20];

ll poow(ll a,ll b){
	ll res=1;
	while(b){
		if(b&1) res=res*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return res;
}

ll C(ll n,ll m){
	if(n<=m) return 1;
	m=min(m,n-m);
	ll res=1,ans=1;
	for(ll i=0;i<m;i++){
		res=res*(n-i)%mod;
		ans=ans*(m-i)%mod;
	}
	return res*poow(ans,mod-2)%mod;
} 

ll lucas(ll a,ll b){
	if(a<b) return 0;
	ll res=1;
	while(b){
		res*=C(a%mod,b%mod);
		res%=mod;
		a/=mod;b/=mod;
	}
	return res;
}

int main(){
	int t,n,s;
	cin>>t;
	for(int ca=1;ca<=t;ca++){
		cin>>n>>s;
		ll x,y;
		for(int i=0;i<n;i++){
			cin>>x>>y;
			s-=x;ve[i]=y-x;
		}
		cout<<"Case "<<ca<<": ";
		ll ans=lucas(s+n-1,n-1);
		ll N=1<<n;
		for(int i=1;i<N;i++){
			ll tem=s;int f=0;
			for(int j=0;j<n;j++){
				if((1<<j)&i){
					f++;
					tem-=ve[j]+1;
				}
			}
			if(tem>=0){
				if(f&1) ans-=lucas(tem+n-1,n-1);
				else ans+=lucas(tem+n-1,n-1);
				ans=(ans+mod)%mod;
			}
		}
		cout<<ans<<"\n";
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值