题目链接:点击进入
题目
题意
2n 个框,从第 2x - 1 个框里可以得到 kx 个球 ( k >= 0 ) ,从第 2x 个框里可以得到 <= x 个球。问得到 m 个球,有多少种取法。
思路
思路一:
根据题意我们大概可以得到,对于一个位置 i ,若是奇数,则可以得到 <= ( i + 1 ) / 2 个球,若是偶数,则可以得到 k * i / 2 个球 ( k >= 0 ) 。不管从哪个框里拿球,都是有限制的。要么是拿某个数的倍数,要么拿比某个数小的数,这里有很多限制条件,不好处理。那我能不能找到一种情况,满足我想拿多少拿多少,变成一种,从好几个可以任意取的框里拿球满足一定数量的情况,这种情况相比与之前的限制拿球的情况要好处理。
如果想要任意拿取,那必须每个数都要有,但是我们要么是某个数的倍数,要么拿比某个数小的数。不能满足啊。想一下,若是对于每个数的倍数 kx ,我要是能满足找到一个 [ 1 , x - 1 ] 的区间,那我不就能取遍所有的数了🐎。而这个 [ 1 , x - 1 ] 的区间不就恰好是位置 2x 前面的位置 2x - 3 的取值🐎。合并合并、凑吧凑吧,2n 个框,就可以合成 n 个可以任意取的框,外加一个可以取 <=n 的框。我们枚举可以取 <=n 的框里取的球数,那么剩下的球就是个定值 p ,那么就变成了从 n 个任意取的框里取 p 个球的情况数。这就相当于,将 p 个球放在 n 个不同框里的方案数,n 个框都可以取 0 ,如果在 n 个框里都预先放入 1 个球,那问题就等价于把 p + n 个球放入 n 个不同框里,且每个框至少一个的方案数,而这恰好就是经典的插板法,问题答案应该是
C
p
+
n
−
1
n
−
1
C_{p+n-1}^{n-1}
Cp+n−1n−1 ( 凑元素插板法,学习链接 )。
答案就是:
∑
i
=
0
n
C
m
−
i
+
n
−
1
n
−
1
\sum_{i=0}^{n}C_{m-i+n-1}^{n-1}
∑i=0nCm−i+n−1n−1
但是要是这样计算答案多半要T,所以我们再化简一下。
将式子展开可以得到:
C
m
+
n
−
1
n
−
1
+
C
m
+
n
−
2
n
−
1
+
.
.
.
+
C
m
n
−
1
+
C
m
−
1
n
−
1
C_{m+n-1}^{n-1}+C_{m+n-2}^{n-1}+...+C_{m}^{n-1}+C_{m-1}^{n-1}
Cm+n−1n−1+Cm+n−2n−1+...+Cmn−1+Cm−1n−1
根据组合数性质 C n m = C n − 1 m − 1 + C n − 1 m C_{n}^{m}=C_{n-1}^{m-1}+C_{n-1}^{m} Cnm=Cn−1m−1+Cn−1m 即 C m n = C m − 1 n − 1 + C m − 1 n C_{m}^{n}=C_{m-1}^{n-1}+C_{m-1}^{n} Cmn=Cm−1n−1+Cm−1n
C m − 1 n − 1 = C m n − C m − 1 n C_{m-1}^{n-1}=C_{m}^{n}-C_{m-1}^{n} Cm−1n−1=Cmn−Cm−1n
C m n − 1 + C m − 1 n − 1 = C m n − 1 + C m n − C m − 1 n = C m + 1 n − C m − 1 n C_{m}^{n-1}+C_{m-1}^{n-1}=C_{m}^{n-1}+C_{m}^{n}-C_{m-1}^{n}=C_{m+1}^{n}-C_{m-1}^{n} Cmn−1+Cm−1n−1=Cmn−1+Cmn−Cm−1n=Cm+1n−Cm−1n
. . . ... ...
C m + n − 1 n − 1 + C m + n − 2 n − 1 + . . . + C m n − 1 + C m − 1 n − 1 = C m + n n − C m − 1 n C_{m+n-1}^{n-1}+C_{m+n-2}^{n-1}+...+C_{m}^{n-1}+C_{m-1}^{n-1}=C_{m+n}^{n}-C_{m-1}^{n} Cm+n−1n−1+Cm+n−2n−1+...+Cmn−1+Cm−1n−1=Cm+nn−Cm−1n
所以最终答案就是:
C
m
+
n
n
−
C
m
−
1
n
C_{m+n}^{n}-C_{m-1}^{n}
Cm+nn−Cm−1n
思路二:
打表找规律,姜佬yyds,最后打表找规律压线过,膜拜膜拜(o゜▽゜)o☆
代码
//#pragma GCC optimize(3)//O3
//#pragma GCC optimize(2)//O2
#include<iostream>
#include<string>
#include<map>
#include<set>
//#include<unordered_map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<fstream>
#define X first
#define Y second
#define best 131
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define lowbit(x) x & -x
#define inf 0x3f3f3f3f
//#define int long long
//#define double long double
//#define rep(i,x,y) for(register int i = x; i <= y;++i)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const int maxn=2e6+10;
const int mod=1e9+7;
const double eps=1e-9;
const int N=5e3+10;
/*--------------------------------------------*/
inline int read()
{
int k = 0, f = 1 ;
char c = getchar() ;
while(!isdigit(c)){if(c == '-') f = -1 ;c = getchar() ;}
while(isdigit(c)) k = (k << 1) + (k << 3) + c - 48 ,c = getchar() ;
return k * f ;
}
/*--------------------------------------------*/
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 f[maxn],inv[maxn];
ll init()
{
f[0]=1;
for(int i=1;i<maxn;i++)
f[i]=f[i-1]*i%mod;
inv[maxn-1]=qpow(f[maxn-1],mod-2);
for(int i=maxn-2;i>=0;i--)
inv[i]=inv[i+1]*(i+1)%mod;
return 0;
}
ll c(ll n,ll m)
{
if (n<m) return 0;
return f[n]*inv[m]%mod*inv[n-m]%mod;
}
int t,n,m;
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);cout.tie(0);
init();
cin>>t;
while(t--)
{
cin>>n>>m;
ll ans=((c(m+n,n)-c(m-1,n))%mod+mod)%mod;
cout<<ans<<endl;
}
return 0;
}