先令
p
=
min
(
p
,
n
−
1
)
p=\min(p,n-1)
p=min(p,n−1),这样可以理解为我们至多能损失
p
p
p只熊。
设
F
[
i
]
[
j
]
F[i][j]
F[i][j]表示还有
i
i
i天,至多还能损失
j
j
j只熊能区分出的最多桶数目,所求即为
F
[
1
]
[
p
]
F[1][p]
F[1][p]~
F
[
q
]
[
p
]
F[q][p]
F[q][p]。那么我们考虑一次操作后会发生的情况,我们会将所有桶根据喝了它的熊的情况划分成
2
n
−
p
+
j
2^{n-p+j}
2n−p+j组,显然能立刻知道酒在哪个组中,不过我们只能保留那些喝了它的熊数目不超过
j
j
j个的组(不然会暴毙)。于是有
F
[
i
]
[
j
]
=
∑
k
=
0
j
(
n
−
p
+
j
k
)
F
[
i
−
1
]
[
j
−
k
]
F[i][j]=\sum_{k=0}^{j} {{n-p+j}\choose{k}}F[i-1][j-k]
F[i][j]=∑k=0j(kn−p+j)F[i−1][j−k],其中
F
[
0
]
[
i
]
=
1
F[0][i]=1
F[0][i]=1。
这样直接递推复杂度过高,运用一点常系数线性递推的知识容易做到
O
(
p
3
+
p
q
)
\mathcal O(p^3+pq)
O(p3+pq)。这里利用一下转移矩阵的性质,有
F
[
i
]
[
p
]
=
n
!
⋅
(
∑
j
=
0
p
1
(
n
−
j
)
!
⋅
[
x
i
]
e
j
x
)
=
∑
j
=
0
p
(
n
j
)
i
j
F[i][p]=n!\cdot (\sum_{j=0}^{p}\frac{1}{(n-j)!}\cdot[x^i]e^{jx})=\sum_{j=0}^{p}{{n}\choose{j}}i^j
F[i][p]=n!⋅(∑j=0p(n−j)!1⋅[xi]ejx)=∑j=0p(jn)ij。于是预处理组合数
m
o
d
2
32
\bmod \ 2^{32}
mod 232的值即可简单计算。
时间复杂度
O
(
p
2
+
p
q
)
\mathcal O(p^2+pq)
O(p2+pq)。
#include <bits/stdc++.h>
using namespace std;
typedef unsigned int ui;
ui pow_mod(ui x,ui k) {
ui ans=1;
while (k) {
if (k&1) ans*=x;
x*=x;
k>>=1;
}
return ans;
}
ui C(ui n,ui m) {
ui s1=1,s2=1;
int cnt=0;
for(int i=1;i<=m;i++) {
ui x=n-i+1;
int s=0;
while (x%2==0) {
x/=2;
s++;
}
s1*=x;cnt+=s;
x=i;s=0;
while (x%2==0) {
x/=2;
s++;
}
s2*=x;cnt-=s;
}
return s1*pow_mod(s2,(1u<<31)-1)*pow_mod(2,cnt);
}
ui Cs[135];
int main() {
int n,m,p;
scanf("%d%d%d",&n,&p,&m);
p=min(p,n-1);
for(int i=0;i<=p;i++) Cs[i]=C(n,i);
ui ans=0;
for(int i=1;i<=m;i++) {
ui s=0,v=1;
for(int j=0;j<=p;j++) {
s+=v*Cs[j];
v*=i;
}
ans^=(i*s);
}
printf("%u\n",ans);
return 0;
}