2021“MINIEYE杯”中国大学生算法设计超级联赛(7)
hdu 7047 Link with Balls
题意:
(这个题面就离谱,看老半天)
-
有 2 n 2n 2n 个桶
第 2 x − 1 2x-1 2x−1 个桶可以拿 k x kx kx 个球( k > = 0 k>=0 k>=0)
第 2 x 2x 2x 个桶最多拿 x x x 个球
求拿取 m m m 个球的方案数
复盘:
(赛时觉得是组合数学,但这变化是真的难以操作,赛后看了大佬的题解发现是还没学的生成函数的板子题)
不会生成函数的先看这篇:这可能是最通俗最详细的生成函数讲解了吧!!!
O
r
z
大
佬
i
s
s
u
e
Orz大佬issue
Orz大佬issue ,看了大佬的博客,我就入门了生成函数
f
(
2
u
−
1
)
=
1
+
x
u
+
x
2
u
+
x
3
u
+
.
.
.
=
1
1
−
x
u
\begin{aligned} f(2u-1) &= 1+x^u+x^{2u}+x^{3u}+...\\ &=\frac{1}{1-x^u} \end{aligned}
f(2u−1)=1+xu+x2u+x3u+...=1−xu1
f
(
2
u
)
=
1
+
x
+
x
2
+
x
3
+
.
.
.
+
x
u
=
1
−
x
u
+
1
1
−
x
\begin{aligned} f(2u) &= 1+x+x^{2}+x^{3}+...+x^u\\ &=\frac{1-x^{u+1}}{1-x} \end {aligned}
f(2u)=1+x+x2+x3+...+xu=1−x1−xu+1
总的生成函数即为:
∏
i
=
1
2
n
f
i
=
(
1
1
−
x
1
1
−
x
2
1
1
−
x
3
.
.
.
1
1
−
x
n
)
(
1
−
x
2
1
−
x
1
−
x
3
1
−
x
1
−
x
4
1
−
x
.
.
.
1
−
x
n
+
1
1
−
x
)
=
1
−
x
n
+
1
(
1
−
x
)
n
+
1
=
(
1
−
x
n
+
1
)
(
1
−
x
)
−
(
n
+
1
)
\begin{aligned} \prod_{i=1}^{2n}{f_i} &= (\frac{1}{1-x}\frac{1}{1-x^2}\frac{1}{1-x^3}...\frac{1}{1-x^n})(\frac{1-x^2}{1-x}\frac{1-x^3}{1-x}\frac{1-x^4}{1-x}...\frac{1-x^{n+1}}{1-x}) \\ &=\frac{1-x^{n+1}}{(1-x)^{n+1}}\\ &=(1-x^{n+1})(1-x)^{-(n+1)} \end{aligned}
i=1∏2nfi=(1−x11−x211−x31...1−xn1)(1−x1−x21−x1−x31−x1−x4...1−x1−xn+1)=(1−x)n+11−xn+1=(1−xn+1)(1−x)−(n+1)
最后我们要求的就是 x m x^m xm 的系数(令其为 [ x m ] [x_m] [xm]):
多项式指数为负数时: ( 1 − x ) − n 的 [ x m ] = ( m n + m − 1 ) 式 1 = ( n − 1 n + m − 1 ) 式 2 (1-x)^{-n}的[x_m]=(_{m}^{n+m-1})_{式1}=(_{n-1}^{n+m-1})_{式2} (1−x)−n的[xm]=(mn+m−1)式1=(n−1n+m−1)式2
由于m有可能大于n,故我们用式2,即为: ( n n + m ) − ( n m − 1 ) (_{n}^{n+m})-(_{n}^{m-1}) (nn+m)−(nm−1)
若用式1: ( m n + m ) − ( m m − 1 ) (_{m}^{n+m})-(_{m}^{m-1}) (mn+m)−(mm−1) ,减数永远为0,会出错
接下来就是套 C n m C_n^m Cnm 的板子了
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5, mo=1e9+7;
int fac[N*2], inv[N*2];
void init(int n)
{
fac[0] = 1;
for(int i=1;i<=n;i++) fac[i] = 1LL*fac[i-1]*i%mo;
inv[0] = inv[1] = 1;
for(int i=2;i<=n;i++) inv[i] = mo - 1LL*(mo/i)*inv[mo%i]%mo;
for(int i=2;i<=n;i++) inv[i] = 1LL*inv[i-1]*inv[i]%mo;
}
inline int C(int n, int m)
{
if(n<0 || m>n) return 0;
return 1LL*fac[n]*inv[m]%mo*inv[n-m]%mo;
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int t;
cin>>t;
init((int)2e6);
while(t--)
{
int n,m;
cin>>n>>m;
int ans= (C(n+m,n)-C(m-1,n)+mo)%mo;
cout<<ans<<endl;
}
return 0;
}