51nod1667 概率好题

考虑计算方案数,令 xi=aili(0xirili) ,得到

l1+x1?r2x2x1+x2?r2l1

x1 x2 并没有本质差别,用插板法解决。取等号时可以直接算,取小于等于时可以加入一个元素来放置多出来的部分。上限用容斥来解决。

#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long
const int maxn=20,p=1000000007;
int l1[maxn],l2[maxn],r1[maxn],r2[maxn],f[maxn],fac[maxn+10],inv[maxn+10],n1,n2,n;
int inc(int x,int y)
{
    x+=y;
    return x>=p?x-p:x;
}
int dec(int x,int y)
{
    x-=y;
    return x<0?x+p:x;
}
int pow(int b,int k)
{
    int r=1;
    for (;k;k>>=1,b=(LL)b*b%p)
        if (k&1) r=(LL)r*b%p;
    return r;
}
int get(int n,int m)
{
    int ret=1;
    for (int i=n+m-1;i>=n+1;i--) ret=(LL)ret*i%p;
    ret=(LL)ret*inv[m-1]%p;
    return ret;
}
int calc(int n,int s)
{
    int ret=0,s1,cnt,x;
    for (int S=0;S<(1<<n);S++)
    {
        cnt=0;
        s1=s;
        for (int i=0;i<n;i++)
            if (S&(1<<i))
            {
                cnt++;
                s1-=f[i]+1;
            }
        if (s1<0) continue;
        x=get(s1,n);
        if (cnt&1) ret=dec(ret,x);
        else ret=inc(ret,x);
    }
    return ret;
}
void solve()
{
    int x,y,z,w,s=1;
    scanf("%d",&n1);
    for (int i=1;i<=n1;i++) scanf("%d%d",&l1[i],&r1[i]);
    scanf("%d",&n2);
    for (int i=1;i<=n2;i++) scanf("%d%d",&l2[i],&r2[i]);
    n=n1+n2;
    w=0;
    for (int i=1;i<=n1;i++) w=dec(w,l1[i]);
    for (int i=1;i<=n2;i++) w=inc(w,r2[i]);
    for (int i=1;i<=n1;i++) f[i-1]=r1[i]-l1[i];
    for (int i=1;i<=n2;i++) f[i+n1-1]=r2[i]-l2[i];
    y=calc(n,w);
    f[n]=w;
    x=calc(n+1,w);
    for (int i=0;i<n;i++) s=(LL)s*(f[i]+1)%p;
    z=dec(s,x);
    x=dec(x,y);
    s=pow(s,p-2);
    x=(LL)x*s%p;
    y=(LL)y*s%p;
    z=(LL)z*s%p;
    printf("%d %d %d\n",z,y,x);
}
int main()
{
    //freopen("a.in","r",stdin);
    fac[0]=1;
    for (int i=1;i<=maxn;i++) fac[i]=(LL)fac[i-1]*i%p;
    for (int i=0;i<=maxn;i++) inv[i]=pow(fac[i],p-2);
    int T;
    scanf("%d",&T);
    while (T--) solve();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值