Codeforces1295F Good Contest-DP

題目大意:

傳送門

長度爲 nn 的數列,第 ii 個數可能的值爲[li,ri][l_i,r_i],求數列爲不嚴格單調遞減數列的期望。2n50,0liri1e9(2\leq n \leq 50,0 \leq l_i \leq r_i \leq 1e9)

Solution:

我們把這些區間分割成兩兩之間不互相覆蓋的若干塊,把這些分割後的區間從左到右標上號,可以得到如下結論:對於任意兩個數 i<ji \lt jii 所屬的區間編號一定大於等於 jj 所屬的區間編號,因此我們可以想到一種 dp 的狀態:dp[i][j]dp[i][j] 表示前 ii 個數,第 ii 個數在第 jj 個區間的合法方案數,轉移時枚舉第 jj 個區間能加多少個數 kk ,轉移方程爲dp[i][j]+=dp[ik][j+1cnt]Clen+k1len1dp[i][j]+=dp[i-k][j+1\sim cnt]*C_{len+k-1}^{len-1}lenlen指的是第 jj 個區間的長度,cntcnt 指的是總區間個數,最後答案就是i=1cntdp[n][i]i=1n(rili+1)\frac {\sum_{i=1}^{cnt}dp[n][i]}{\prod_{i=1}^n(r_i-l_i+1)}

代碼:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int mod=998244353;
int n;
int l[55],r[55],lsh[110],cnt;
int dp[55][110],sum;
int fast_pow(int a,int x)
{
	int ans=1;
	for (;x;x>>=1,a=1ll*a*a%mod)
		if (x&1) ans=1ll*ans*a%mod;
	return ans;
}
int C(int x,int y)
{
	int ans=1;
	for (int i=1;i<=x;i++)
		ans=1ll*ans*(y+1-i)%mod*fast_pow(i,mod-2)%mod;
	return ans;
}
int main()
{
	scanf("%d",&n);sum=1;
	for (int i=1;i<=n;i++)
	{
		scanf("%d%d",&l[i],&r[i]);
		r[i]++;lsh[++cnt]=l[i];lsh[++cnt]=r[i];
		sum=1ll*sum*(r[i]-l[i])%mod;
	}
	sort(lsh+1,lsh+1+cnt);
	cnt=unique(lsh+1,lsh+1+cnt)-lsh-1;
	for (int i=1;i<=n;i++) l[i]=lower_bound(lsh+1,lsh+1+cnt,l[i])-lsh;
	for (int i=1;i<=n;i++) r[i]=lower_bound(lsh+1,lsh+1+cnt,r[i])-lsh;
	for (int i=1;i<=cnt;i++) dp[0][i]=1;
	for (int i=1;i<=n;i++)
	{	
		for (int j=l[i];j<r[i];j++)
		{
			for (int k=i;k>0;k--)
			{
				if (j<l[k]||j>=r[k]) break;
				dp[i][j]=(dp[i][j]+1ll*dp[k-1][j+1]*C(i-k+1,i-k+lsh[j+1]-lsh[j]))%mod;
			}
		}
		for (int j=cnt-1;j>=1;j--)
		{
			dp[i][j]+=dp[i][j+1];if (dp[i][j]>=mod) dp[i][j]-=mod;
		}
	}
	printf("%d",1ll*dp[n][1]*fast_pow(sum,mod-2)%mod);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章