• 2025-06-10
  • 本场的题解(劳N没有把题目开放,所以我只好写在这里了,生蚝会写ABCD的题解)

  • @ 2025-6-12 9:19:24

E

显然我们考虑每个格子的贡献,说白了这个题就是让你把每个点被涂黑的概率加起来,这很好理解。

然后我们考虑第 ii 行第 jj 列的贡献,其实就是如果选的两个格子在其左上,右上,左下,右下的话就一定能覆盖掉这个格子,这一部分的贡献是 2ij(ni+1)(mj+1)2ij(n-i+1)(m-j+1),然后我们要减去两个选择的格子在同一行和同一列的贡献,因为他们被计算了两次,也就是i(ni+1)+j(mj+1)i*(n-i+1)+j*(m-j+1),最后加加减减一些常数(具体我也不好说,因为这个题是否允许两个格子相等也并不明确)

然后这是如果只选一次,它能够变黑的概率,那么kk次只要有一次变黑它就黑了,所以我们只需要计算 (1p)k(1-p)^k,就可以退出来它变黑的概率统计增加即可。

F

神仙题

首先我们先忽略精度问题,考虑直接硬干怎么做。发现这个 2(x+y)2^(x+y)真的很难办,我们不妨把它的贡献拆开。注意到!!!这个东西它的贡献其实可以理解为这 x+yx+y 个行或列构成的集合中选出一个子集的方案。然后这个题就快做完了,我们只需要枚举每一个可能的子集,计算它带来的贡献就赢了,具体贡献方式我会放出来代码。

然后还有一些实现细节我都在代码里体现。

CODE

#include<bits/stdc++.h>
#define ld long double 
using namespace std;
int n,m,k;
ld res;
ld lnfac[1000005];
inline ld lnC(int n,int m){return lnfac[n]-lnfac[n-m]-lnfac[m];}
int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=m;i++)lnfac[i]=lnfac[i-1]+log(1.0*i);//这个有点厉害,我们可以直接取ln,避免后面精度丢失更为严重的乘法和除法。 
	for(int i=0;i<=n;i++){
		for(int j=0;j<=n;j++){
			int num=i*n+j*n-i*j;
			if(num<=k)res+=exp(lnC(n,i)+lnC(n,j)/*前面是部分一*/+lnC(m-num,k-num)/*这是部分二*/-lnC(m,k));
			
			//我来具体说一下贡献方式,首先我们枚举行和列分别为 $i$ $j$ ,然后我们考虑从n行n列里面把他选出来(对应上面的部分1),这个时候剩下的随便选
			//考虑剩下来的怎么个随便选法,其实就是从总个数m里面先挖去已经确定的位置 $num$ ,然后从里面选出来剩下的 $0$ 也就是 $k-num$
			//这个时候你可能会问,它题目不是先往里面填互不相同的数么?你这样不就只剩下01了?对,但是你注意到这两个问题其实是等价的,我不好证明,因为我直观感觉这很对。 
		}
	}
	if(res>1e99)res=1e99;
	printf("%.6Lf",res);
	return 0;
}

1 条评论

  • 1