题目链接
解题思路
An
interesting
problem.
\textsf{An interesting problem.}
An interesting problem.
我们把问题的要求这样分开:
满足球有标号的标上
A
A
A,满足盒子有标号的标上
B
B
B,满足至多放一个球的标
C
1
C_1
C1,满足至少放一个球的标
C
2
C_2
C2。
p
=
998244353
p=998244353
p=998244353 为模数。
Type 1 : A B 1:AB 1:AB
I : A B \mathrm{I}:AB I:AB
Rating:2
stars(Easy).
\color{skyblue}\textsf{Rating:2 stars(Easy).}
Rating:2 stars(Easy).
每个球都有
m
m
m 个盒子可选,一共
n
n
n 个球。
显然答案为
m
n
m^n
mn。
时间复杂度
O
(
log
n
)
(
≈
O
(
1
)
)
\Omicron(\log n)(\approx\Omicron(1))
O(logn)(≈O(1))。
I I : A B C 1 \mathrm{I\!I}:ABC_1 II:ABC1
Rating:2
stars(Easy).
\color{skyblue}\textsf{Rating:2 stars(Easy).}
Rating:2 stars(Easy).
n
>
m
n>m
n>m 时,盒子装不下球,显然答案为
0
0
0。
否则答案显然为
A
m
n
A_m^n
Amn。
时间复杂度
O
(
log
p
)
(
≈
O
(
1
)
)
\Omicron(\log p)(\approx\Omicron(1))
O(logp)(≈O(1))。
I I I : A B C 2 \mathrm{I\!I\!I}:ABC_2 III:ABC2
Rating:4
stars(Normal).
\color{ForestGreen}\textsf{Rating:4 stars(Normal).}
Rating:4 stars(Normal).
n
<
m
n<m
n<m 时显然答案为
0
0
0。
否则,第二类Stirling数的意义就是把不同的球放到同样的盒子里。现在盒子不一样,全排列不就行了?
答案为
m
!
{
n
m
}
m!\begin{Bmatrix}n\\m\end{Bmatrix}
m!{nm}。(其实
V
I
\mathrm{V\!I}
VI 就是先计算这玩意再乘上
1
m
!
\dfrac 1 {m!}
m!1)
时间复杂度
O
(
m
log
n
m
p
)
(
≈
O
(
m
)
)
\Omicron(m\log nmp)(\approx\Omicron(m))
O(mlognmp)(≈O(m))。
Type 2 : A 2:A 2:A
I V : A \mathrm{I\!V}:A IV:A
Rating:6
stars(Hard).
\color{ffd000}\textsf{Rating:6 stars(Hard).}
Rating:6 stars(Hard).
看起来这玩意很像第二类Stirling数(
V
I
\mathrm{V\!I}
VI)。但是,又不是。少了一个集合非空的条件。
那么,我们能不能把它的公式改一改呢?我没试过。不过,我们可以用另外一种方法。
枚举有几个盒子有球。我们得到
∑
i
=
1
min
(
m
,
n
)
{
n
i
}
\sum_{i=1}^{\min(m,n)}\begin{Bmatrix}n\\i\end{Bmatrix}
i=1∑min(m,n){ni}
好的,第二类Stirling数(行)的板子即可。
时间复杂度
O
(
n
log
n
p
)
(
≈
O
(
n
log
n
)
)
\Omicron(n\log np)(\approx\Omicron(n\log n))
O(nlognp)(≈O(nlogn))。
V : A C 1 \mathrm{V}:AC_1 V:AC1
Easiest
Subtask.
\color{skyblue}\textsf{Easiest Subtask.}
Easiest Subtask.
Rating:1
star(Easy).
\color{skyblue}\textsf{Rating:1 star(Easy).}
Rating:1 star(Easy).
显然装得下是
1
1
1,装不下是
0
0
0。
时间复杂度
O
(
1
)
\Omicron(1)
O(1)。
V I : A C 2 \mathrm{V\!I}:AC_2 VI:AC2
Rating:3
stars(Normal).
\color{ForestGreen}\textsf{Rating:3 stars(Normal).}
Rating:3 stars(Normal).
n
<
m
n<m
n<m 时显然答案为
0
0
0。
否则答案显然为
{
n
m
}
\begin{Bmatrix}n\\m\end{Bmatrix}
{nm}。
时间复杂度
O
(
m
log
n
m
p
)
(
≈
O
(
m
)
)
\Omicron(m\log nmp)(\approx\Omicron(m))
O(mlognmp)(≈O(m))。
Type 3 : B 3:B 3:B
V I I : B \mathrm{V\!I\!I}:B VII:B
Rating:4
stars(Normal).
\color{ForestGreen}\textsf{Rating:4 stars(Normal).}
Rating:4 stars(Normal).
我们考虑先让每个盒子放一个球(即设球数为
n
+
m
n+m
n+m),即转化成
I
X
\mathrm{I\!X}
IX。
时间复杂度
O
(
log
p
)
(
≈
O
(
1
)
)
\Omicron(\log p)(\approx\Omicron(1))
O(logp)(≈O(1))。
V I I I : B C 1 \mathrm{V\!I\!I\!I}:BC_1 VIII:BC1
Rating:2
stars(Easy).
\color{skyblue}\textsf{Rating:2 stars(Easy).}
Rating:2 stars(Easy).
n
>
m
n>m
n>m 时,盒子装不下球,显然答案为
0
0
0。
否则答案显然为
C
m
n
C_m^n
Cmn。
时间复杂度
O
(
log
p
)
(
≈
O
(
1
)
)
\Omicron(\log p)(\approx\Omicron(1))
O(logp)(≈O(1))。
I X : B C 2 \mathrm{I\!X}:BC_2 IX:BC2
Rating:3
stars(Normal).
\color{ForestGreen}\textsf{Rating:3 stars(Normal).}
Rating:3 stars(Normal).
用插板法可得答案为
C
n
−
1
m
−
1
C_{n-1}^{m-1}
Cn−1m−1。
时间复杂度
O
(
log
p
)
(
≈
O
(
1
)
)
\Omicron(\log p)(\approx\Omicron(1))
O(logp)(≈O(1))。
Type 4 : ∅ 4:\emptyset 4:∅
X : ∅ \mathrm{X}:\emptyset X:∅
Rating:8
stars(Harder).
\color{ff5500}\textsf{Rating:8 stars(Harder).}
Rating:8 stars(Harder).
我们要求的答案是把
n
n
n 划分为
m
m
m 个自然数的方案数。设它为
p
n
,
m
p_{n,m}
pn,m,有
p
n
,
m
=
p
n
−
m
,
m
+
p
n
,
m
−
1
p_{n,m}=p_{n-m,m}+p_{n,m-1}
pn,m=pn−m,m+pn,m−1。考虑优化,设多项式
F
i
(
x
)
=
∑
j
=
0
∞
p
j
,
i
x
j
F_i(x)=\sum_{j=0}^\infty p_{j,i}x^j
Fi(x)=j=0∑∞pj,ixj
则有
F
i
(
x
)
=
F
i
−
1
(
x
)
∑
j
=
0
∞
x
j
i
=
F
i
−
1
(
x
)
1
−
x
i
=
∏
j
=
1
i
1
1
−
x
j
F_i(x)=F_{i-1}(x)\sum_{j=0}^\infty x^{ji}=\frac{F_{i-1}(x)}{1-x^i}=\prod_{j=1}^i\frac 1{1-x^j}
Fi(x)=Fi−1(x)j=0∑∞xji=1−xiFi−1(x)=j=1∏i1−xj1
参考付公主的背包(P4389) 的
ln
+
exp
\ln+\exp
ln+exp 法,可得
∏
j
=
1
i
1
1
−
x
j
=
exp
∑
j
=
1
i
(
−
ln
(
1
−
x
j
)
)
=
exp
∑
j
=
1
i
∑
k
=
1
∞
x
j
k
k
\prod_{j=1}^i\frac 1{1-x^j}=\exp\sum_{j=1}^i(-\ln(1-x^j))=\exp\sum_{j=1}^i\sum_{k=1}^\infty \frac {x^{jk}} k
j=1∏i1−xj1=expj=1∑i(−ln(1−xj))=expj=1∑ik=1∑∞kxjk
我们要求的即为
[
x
n
]
F
m
=
[
x
n
]
exp
∑
i
=
1
m
∑
j
=
1
∞
x
i
j
j
[x^n]F_m=[x^n]\exp\sum_{i=1}^m\sum_{j=1}^\infty \frac {x^{ij}} j
[xn]Fm=[xn]expi=1∑mj=1∑∞jxij
X I : C 1 \mathrm{X\!I}:C_1 XI:C1
Easiest
Subtask.
\color{skyblue}\textsf{Easiest Subtask.}
Easiest Subtask.
Rating:1
star(Easy).
\color{skyblue}\textsf{Rating:1 star(Easy).}
Rating:1 star(Easy).
显然装得下是
1
1
1,装不下是
0
0
0。
时间复杂度
O
(
1
)
\Omicron(1)
O(1)。
X I I : C 2 \mathrm{X\!I\!I}:C_2 XII:C2
Rating:9
stars(Insane).
\color{dd55dd}\textsf{Rating:9 stars(Insane).}
Rating:9 stars(Insane).
我们先放
m
−
n
m-n
m−n 个球进盒子里,便可转化为
X
\mathrm{X}
X。
时间复杂度为
O
(
n
log
n
)
\Omicron(n\log n)
O(nlogn)(可使用
X
\mathrm{X}
X 的结果直接回答,真实复杂度为
O
(
1
)
\Omicron(1)
O(1))。
代码实现
//
#ifndef Polynomial_Class
//这里是长为13KB的多项式全家桶,由于篇幅原因省略
#endif
using namespace std;
using namespace Polynomial;
array<long long,400001> facts,inverses;
polynomial<524288> poly_n_4,poly_m_4,poly_4,poly_exp,poly_ans;
int main(int argc,char* argv[],char* envp[])
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
facts[0]=1;
for(int i=1;i<=400000;i++)
facts[i]=facts[i-1]*i%prime;
long long cntbox,cntball;
cin>>cntball>>cntbox;
cout<<fast_pow(cntbox,cntball,prime)<<'\n'<<(cntball>cntbox?0:facts[cntbox]*inverse(facts[cntbox-cntball],prime)%prime)<<'\n';
long long ans_3=0;
if(cntball<cntbox)
{
cout<<0<<'\n';
goto endcase_3;
}
for(int i=0;i<=cntbox;i++)
ans_3=(ans_3+fast_pow(prime-1,i,prime)*facts[cntbox]%prime*inverse(facts[i]*facts[cntbox-i]%prime,prime)%prime*fast_pow(cntbox-i,cntball,prime)%prime)%prime;
cout<<ans_3<<'\n';
endcase_3:;
long long ans_4=0;
for(int i=0;i<=cntball;i++)
poly_n_4[i]=fast_pow(i,cntball,prime)*inverse(facts[i],prime)%prime,poly_m_4[i]=fast_pow(prime-1,i,prime)*inverse(facts[i],prime)%prime;
mult(cntball+1,cntball+1,poly_n_4,poly_m_4,poly_4);
for(int i=1;i<=min(cntball,cntbox);i++)
ans_4=(ans_4+poly_4[i])%prime;
cout<<ans_4<<'\n'<<(cntball<=cntbox)<<'\n'<<ans_3*inverse(facts[cntbox],prime)%prime<<'\n'
<<facts[cntball+cntbox-1]%prime*inverse(facts[cntbox-1]*facts[cntball]%prime,prime)%prime<<'\n'
<<(cntbox<cntball?0:facts[cntbox]%prime*inverse(facts[cntball]*facts[cntbox-cntball]%prime,prime)%prime)<<'\n'
<<(cntbox>cntball?0:facts[cntball-1]%prime*inverse(facts[cntbox-1]*facts[cntball-cntbox]%prime,prime)%prime)<<'\n';
for(int i=1;i<=cntball;i++)
inverses[i]=inverse(i,prime);
for(int i=1;i<=min(cntbox,cntball);i++)
for(int j=1;j*i<=cntball;j++)
poly_exp[i*j]=(poly_exp[i*j]+inverses[j])%prime;
exp(cntball+1,poly_exp,poly_ans);
cout<<poly_ans[cntball]<<'\n'<<(cntball<=cntbox)<<'\n'<<(cntball<cntbox?0:poly_ans[cntball-cntbox]);
return 0;
}