考虑喝过一桶酒或果汁的熊的集合,集合中的元素是一个二元组
(
x
,
t
x
)
(x,t_x)
(x,tx) 表示熊的编号以及第几天和的,注意到如果一只熊和了这桶果汁没倒那么不会再喝,如果倒了那么也不会再和,那么每桶果汁或酒的集合就形如
{
(
x
,
t
x
)
}
\{(x,t_x)\}
{(x,tx)} 其中
x
x
x 只出现一次,若两个集合不同则可以区分它们,床的限制是对集合大小的限制,那么容易发现答案即为
a
n
s
t
=
∑
i
=
0
min
(
n
−
1
,
p
)
(
n
i
)
t
i
ans_t=\sum_{i=0}^{\min (n-1,p)}\binom{n}{i}t^i
anst=i=0∑min(n−1,p)(in)ti 组合数考虑算
n
i
‾
i
!
\frac{n^{\underline i}}{i!}
i!ni,暴力约分,复杂度
O
(
p
2
log
+
q
p
)
O(p^2\log +qp)
O(p2log+qp)
#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
typedef unsigned int ui;
cs int N =150;
ui q;int n, p, a[N], b[N]; ui c[N];intmain(){
#ifdef FSYolanda
freopen("1.in","r",stdin);
#endif
scanf("%d%d%d",&n,&p,&q);
p =min(p,n-1); c[0]=1;for(int i=1; i<=p; i++) a[i]= i, b[i]= n-i+1;for(int i=1; i<=p; i++){for(int j=1; j<=i; j++){int t =__gcd(b[i],a[j]);
a[j]/=t; b[i]/=t;}for(int j=1; j<i; j++){int t =__gcd(b[j],a[i]);
a[i]/=t; b[j]/=t;} c[i]=1;for(int j=1; j<=i; j++) c[i]= c[i]*(ui)b[j];} ui ans =0;for(int t=1; t<=q; t++){
ui now =0, mt =1;for(int i=0; i<=p; i++)
now += mt * c[i], mt *=(ui)t;
ans ^=(ui)t * now;} cout << ans;return0;}