卧薪尝胆,厚积薄发。
概率好题
Date: Fri Aug 24 10:58:29 CST 2018
In Category:
NoCategory
Description:
甲乙各有
$k_1,k_2$
个区间,每次随机从每个区间中挑出一个数求和,问
$S_1>S_2$
,
$S_1=S_2$
,
$S_1<S_2$
概率。
$1\le k \le 8,1\le l,r\le 10^7$
Solution:
若
$S_1>S_2$
,设甲选的数为
$R_i-x_i,x_i\in[0,R_i-L_i]$
,乙选的数为
$L_i+y_i,y_i\in[0,R_i-L_i]$
,于是
$\sum R_i-\sum x_i>\sum L_i+\sum y_i$
,变形为
$\sum R_i-\sum L_i>\sum y_i+\sum x_i$
,
$\sum R_i-\sum L_i-1=\sum y_i+\sum x_i+k,k\in[0,+\infty)$
。
这个方程每个未知量都有上限,求解的个数,可以容斥,设
$S(i)$
表示至少有
$i$
个未知量不满足条件的方案数,则
$\begin{align}ans=\sum_{i=0}^n(-1)^i\times S(i)\end{align}$
,枚举每个未知数是否符合,如果他不符合,那么
$x_i>up_i$
,即
$x_i-up_i-1\ge 0$
,那就在等式右边减掉
$up_i+1$
。于是又变成了一个有下界的方程,且一定有大于等于个不符合,每个未知数只要
$\ge 0$
即可,于是插板法就行了,组合数由于
$n$
很小可以直接算。
简单来说这题就是由于
$k$
很小,可以通过容斥把等于零变成大于等于零,于是没有上限可以用插板法解决。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int n,k1,k2;
typedef long long ll;
#define MOD 1000000007
ll power(ll a,int b)
{
ll res = 1;
while(b > 0)
{
if(b & 1)res = res * a % MOD;
a = a * a % MOD;
b = b >> 1;
}
return res;
}
ll C(int n,int m)
{
ll res = 1;
for(int i = n - m + 1;i <= n;++i)res = res * i % MOD;
for(int i = 1;i <= m;++i)res = res * power(i,MOD - 2) % MOD;
return res;
}
#define MAXK 9
ll u[MAXK << 1];
ll sum;
ll ans;
void dfs(int pos,ll tmp,int type)
{
if(pos == n + 1)
{
if(tmp < 0)return;
ans = (ans + type * C(tmp + n,n) + MOD) % MOD;
return;
}
tmp -= u[pos] + 1;dfs(pos + 1,tmp,-type);
tmp += u[pos] + 1;dfs(pos + 1,tmp,type);
return;
}
void work()
{
scanf("%d",&k1);
int l,r;
sum = 0;
for(int i = 1;i <= k1;++i)
{
scanf("%d%d",&l,&r);
u[i] = r - l;sum += r;
}
scanf("%d",&k2);
for(int i = 1;i <= k2;++i)
{
scanf("%d%d",&l,&r);
u[k1 + i] = r - l;sum -= l;
}
n = k1 + k2;
u[n + 1] = 1000000000;
--sum;
ll ans1 = 0,ans2 = 0,ans3 = 0;
if(sum < 0)ans1 = 0;
else
{
ans = 0;
dfs(1,sum,1);
ans1 = ans;
}
ans = 0;++sum;
if(sum < 0)ans = 0;
else dfs(1,sum,1);
ans2 = (ans - ans1 + MOD) % MOD;
for(int i = 1;i <= n;++i)
{
ans1 = ans1 * power(u[i] + 1,MOD - 2) % MOD;
ans2 = ans2 * power(u[i] + 1,MOD - 2) % MOD;
}
ans3 = (1 - ans1 + MOD - ans2 + MOD) % MOD;
cout << ans1 << " " << ans2 << " " << ans3 << endl;
return;
}
int main()
{
int testcases = 0;
scanf("%d",&testcases);
while(testcases--)work();
return 0;
}
In tag:
数学-容斥原理
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡