CF643FBears and Juice【组合数学】

正题

题目链接:https://www.luogu.com.cn/problem/CF643F


题目大意

题目有点奇怪就直接放翻译了

\(n\) 只熊和若干桶果汁和恰好一桶酒,每一天每只熊会选择一些桶(可能不选)并各喝一 杯,喝到酒的熊会去睡觉并不再回来,通过这个信息,熊们想知道哪个桶里是酒。

只有 \(p\) 个睡 觉的位置,当睡觉的熊超过了 \(p\) 只或者所有熊都在睡觉时熊们就失败了。

\(R_i\) 表示在 \(i\) 天内桶的数量最多少,使得熊可以成功知道酒的位置。令 \(X_i = (i\times R_i) \bmod 2^{32}\),你需要求出 \(X_1 \oplus X_2 \oplus\ldots \oplus X_q\)

\(1\leq n\leq 10^9\)\(1\leq p\leq 130\)\(1\leq q \leq 2\times 10^6\)


解题思路

之前在XJ杂题选讲时候的神奇题目

题目比较乱但是我们发现题目问的是最多的数量,而不是最劣情况下的最多数量,所以这个东西是在最优情况下能分辨的数量。

这是我们之前很少接触的一种形式,这里需要用到信息的概念,因为我们是最优的,相当于我们所有的情况都可以去尝试,也就是每种信息都可以为我们选出一个答案,那么显然我们让选出的这些答案两两不同肯定就是最优的,所以这里的\(R_i\)就表示\(i\)天以内我们能够获取的信息的数量

那么我们现在能够得到的信息数就是有多少头熊睡着了,和分别在哪一天睡着的,那么有

\[R_i=\sum_{j=1}^{min\{p-1,n\}}\binom{n}{j}i^j \]

也就是组合睡觉的熊,然后每个睡觉的都可以在任意天的时候睡觉

这个东西主要是\(\binom{n}{j}\)因为没有逆元比较麻烦,但是因为\(j\)比较小所以我们可以直接暴力枚举上下的因子然后消掉他们的\(gcd\)就好了

时间复杂度\(O(p^3\log p+q\times p)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int n,p,q;
unsigned ans,f[300];
vector<int> a,b;
int main()
{
	scanf("%d%d%d",&n,&p,&q);
	p=min(n-1,p);
	for(int i=0;i<=p;i++){
		a.clear();b.clear();f[i]=1;
		for(int j=0;j<i;j++)a.push_back(n-j);
		for(int j=1;j<=i;j++)b.push_back(j);
		for(int x=0;x<a.size();x++)
			for(int y=0;y<b.size();y++){
				int d=__gcd(a[x],b[y]);
				a[x]/=d;b[y]/=d;
			}
		for(int x=0;x<a.size();x++)f[i]=1u*a[x]*f[i];
	}
	for(int i=1,t=1;i<=q;i++){
		unsigned tmp=0,k=1;
		for(int j=0;j<=p;j++,k=1u*i*k)
			tmp+=f[j]*k;
		ans^=1u*i*tmp;
	}
	printf("%u",ans);
}
原文地址:https://www.cnblogs.com/QuantAsk/p/14578713.html