其他分享
首页 > 其他分享> > CF1295F Good Contest

CF1295F Good Contest

作者:互联网

written on 2022-05-06

写了三天了,写篇题解加深一下印象。

首先分析题意。我们发现最后的概率是以 分子乘以分母逆元的形式 出现的,然后这又是一道概率题。那么我们就可以考虑直接算满足的方案数了,因为最后的总方案数十分好算,就是所有长度相乘。

题目的限制是单调不增,直观的想法是用 \(f_{i,j}\) 记录第 \(i\) 个区间选数为 \(j\) 的情况,转移很显然。但是一看数据 \(0≤l i≤r i≤998244351\) ,直接作废。

考虑优化,观察到 \(n\) 的范围很小,一般的想法是不是直接对这些区间进行离散化?没错,离散化之后的区间被分成了一小段一小段,而且最多只有 \(2n\) 个,这给我们的启示就是,可不可以通过这些段来转移?

答案是肯定的,我们记 \(f_{i,j}\) 为选到 \(i\) 个位置,此时选择第 \(j\) 个小区间的总方案数。注意,此时我们不能直接由 \(i-1\) 转移而来,因为即使在同一小区间内也不能满足 \(a_i \ge a_i-1\) ,所以转移的时候,我们应当一段数一起转移,这样的话,利用插板法,我们就可以巧妙地规避这样的问题。

插板法: \(n\) 个箱子塞 \(m\) 个相同小球的方案数为\(\dbinom{n+m-1}{n}\) .

那么转移就显然了。要注意的一点是对于一个枚举的 \(k\) ,它必须要包含所在的这个小区间才行,否则就要直接跳出循环。

最后满足条件的方案数就是 \(\sum_{i=1}^{cnt} f_{n,i}\) ,再乘以总方案逆元即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
ll power(ll a,ll b)
{
	if(!b) return 1ll;
	if(b&1) return a*power(a,b-1)%mod;
	ll res=power(a,b>>1)%mod;
	return res*res%mod;
}
ll inv(ll a){return power(a,mod-2);}
ll C(int a,int b)
{
	if(b>a/2) b=a-b;
	ll res=1;
	for(int i=1;i<=b;i++) res=res*1ll*(a-i+1)%mod*inv(1ll*i)%mod;//边乘边除
	return res;
}
int n,l[55],r[55];
int tot,tmp[105];
ll f[55][105];
int main()
{
	scanf("%d",&n);
	ll fm=1;
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&l[i],&r[i]);
		fm=fm*1ll*(r[i]-l[i]+1)%mod;
		tmp[++tot]=l[i],tmp[++tot]=++r[i];
	}
	sort(tmp+1,tmp+1+tot);
	int cnt=unique(tmp+1,tmp+1+tot)-tmp-1;
	for(int i=1;i<=n;i++) l[i]=lower_bound(tmp+1,tmp+1+cnt,l[i])-tmp,r[i]=lower_bound(tmp+1,tmp+1+cnt,r[i])-tmp;
	for(int i=1;i<=cnt;i++) f[0][i]=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=l[i];j<r[i];j++)
		{
			int len=tmp[j+1]-tmp[j];
			for(int k=i-1;k>=0;k--)
			{
				if(l[k+1]>j||r[k+1]<=j) break;//所以只要有一个不满足(区间不包含j这个区间)就不继续累加 
				//小于等于是因为r是加一后的值(r<j就退出) 
				f[i][j]=(f[i][j]+f[i-1][j+1]*C(len+i-k-1,i-k)%mod)%mod;//因为在上面的k~i这部分都选编号为j的这个区间
				//n个箱子塞m个相同小球的方案数为C(n+m-1,n); 
			}
		}
		for(int j=cnt-1;j>=1;j--) f[i][j]=(f[i][j]+f[i][j+1])%mod;
	}
/*	for(int i=1;i<=n;i++) printf("l=%d r=%d\n",l[i],r[i]);
	for(int i=1;i<=n;i++) for(int j=1;j<=cnt;j++) printf("i=%d j=%d val=%lld\n",i,j,f[i][j]);*/
	//fz  f[n][1]
	printf("%lld",f[n][1]*inv(fm)%mod);
}

标签:Good,return,power,Contest,int,ll,区间,CF1295F,mod
来源: https://www.cnblogs.com/Freshair-qprt/p/16537757.html