Codeforces 1295F. Good Contest dp+组合数学+概率

题意

给你n个区间, [ l i , r i ] [l_i,r_i] ,在每个区间里面选整数然后要求选出的整数递减的概率

分析

很老的套路了,考虑分母就是 Π i = 1 n ( r i l i + 1 ) \Pi_{i=1}^{n}{(r_i - l_i + 1)}
分子的话就是单调递减的dp,右端点+1变成左闭右开离散化之后考虑两个相邻的区间我们怎么选数
下一个区间选的数要在上一个的右边
然后如果在同一个区间里面选数:
如果是整数范围的话就可重复组合,实数范围内的话就是 1 / n ! 1/n!
枚举有多少个数在同一个区间内就好了

代码

#include <set> 
#include <map>
#include <cmath>
#include <ctime>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cstdio>
#include <vector> 
#include <cstdlib>
#include <cstring>
#include <climits>
#include <complex>
#include <iostream>
#include <algorithm>

#define fi first
#define se second
#define MP make_pair
#define PB push_back
#define dmp(x) cout << (x) << endl;

using namespace std;

typedef unsigned long long ull;
typedef long long ll;
typedef pair<ll,ll> pii;

const ll N = 110;
const ll mod = 998244353;
const ll inf = 1e15;

inline ll read()
{
  ll p=0; ll f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f*=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}

ll l[N],r[N],n; ll b[N],blen;

ll f[N][N][N]; ll p[N];

ll qpow(ll x,ll k,ll mo)
{
  ll s = 1;
  while(k)
  {
    if(k&1) s = s*x%mo;
    x=x*x%mo; k>>=1;
  }return s;
}

ll inv(ll x){return qpow(x,mod-2,mod);}

ll C(ll x,ll k)
{
  ll s = 1;
  if(k==0) return 1;
  for(ll i=1;i<=k;i++) s = s * (x-i+1) % mod * inv(i) % mod;
  return s;
}

int main()
{
	
  n = read(); blen = 0;
  for(ll i=1;i<=n;i++) l[i] = read(),r[i] = read() , b[++blen] = l[i],b[++blen] = ++r[i];
  ll fm = 1;
  for(ll i=1;i<=n;i++) fm = fm * (r[i] - l[i]) % mod;
  sort(b+1,b+blen+1); blen = unique(b+1,b+blen+1) - (b+1);
  for(ll i=1;i<=n;i++) l[i] = lower_bound(b+1,b+blen+1,l[i]) - b, r[i] = lower_bound(b+1,b+blen+1,r[i]) - b - 1;
  for(ll i=1;i<blen;i++) p[i] = b[i+1] - b[i];
  for(ll i=l[1];i<=r[1];i++) f[1][i][1] = p[i];
  for(ll i=2;i<=n;i++)
    for(ll j=l[i];j<=r[i];j++)
      for(ll t=1;t<i;t++)
        for(ll k=r[i-1];k>=l[i-1];k--)
        {
          if(k<j) break;
          if(j==k)
          {
            f[i][j][t+1] = (f[i][j][t+1] + f[i-1][k][t] * inv(C(p[j]+t-1,t)) % mod * C(p[j]+t,t+1) % mod) % mod;
            break;
          }
          else
          {
            f[i][j][1] = (f[i][j][1] + f[i-1][k][t] * p[j] % mod) % mod;
          }
        }
  
  ll fz = 0;
  for(ll i=1;i<blen;i++)
  {
    for(ll t=1;t<=n;t++) fz = (fz + f[n][i][t]) % mod;
  }

  return printf("%lld\n",fz * inv(fm) % mod),0;
}

猜你喜欢

转载自blog.csdn.net/weixin_39708759/article/details/104120465