zoukankan      html  css  js  c++  java
  • 51nod1667 概率好题

    基准时间限制:4 秒 空间限制:131072 KB 分值: 640 
    甲乙进行比赛。
    他们各有k1,k2个集合[Li,Ri]
    每次随机从他们拥有的每个集合中都取出一个数
    S1=sigma甲取出的数,S2同理
    若S1>S2甲胜 若S1=S2平局 否则乙胜
    分别求出甲胜、平局、乙胜的概率。
    (显然这个概率是有理数,记为p/q,则输出答案为(p/q)%(1e9+7))(逆元)
    注意 多组数据
    Input
    一个数,数据组数(T<=5)
    对于每组数据 输入顺序为
     k1 L1 R1...Lk1 Rk1
    k2 L1 R1...Lk2 Rk2
    (k1,k2<=8,1<=L<=R<=10^7)
    Output
    甲胜、平局、乙胜的概率。
    (显然这个概率是有理数,记为p/q,则输出答案为(p/q)%(1e9+7))(逆元)
    Input示例
    1
    1 1 2
    1 1 4
    Output示例
    125000001 250000002 625000005

    数学问题 容斥

    $[L_i,R_i]$的限制看上去很迷,不怎么好做。

    如果能去掉下界的话,原问题似乎可以转化成容斥求方程解的个数的问题。

    我们来试试去掉下界:

    设前ki个集合为 $R_i - x_i$,后ki个集合为 $ L_i + x_i $

    此时x的取值范围是 $[0,R_i - L_i]$

    那么甲赢乙的情况需要满足的条件是:

    $$sum_{i=1}^{k_1} R_i-x_i > sum_{j=1}^{k_2} L_j+y_j $$

    $$sum_{i=1}^{k_1} x_i + sum_{j=1}^{k_2} y_j< sum_{i=1}^{k_1} R_i -sum_{j=1}^{k_2} L_j $$

    我们惊喜地发现右边是常数,那么可以用组合数+容斥算方程解的个数辣

    甲乙平手的情况,只需要把上面的大于换成等于号即可。

    乙赢甲的情况,可以把上式取负计算解个数,也可以直接用总方案数减去前两问方案数。

    总方案数当然就是所有的$R_i-L_i+1$的乘积

    答案当然就是满足条件的方案数除以总方案数 

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<queue>
     6 #define LL long long
     7 using namespace std;
     8 const int mod=1e9+7;
     9 const int mxn=100001;
    10 int read(){
    11     int x=0,f=1;char ch=getchar();
    12     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    13     while(ch>='0' && ch<='9'){x=x*10-'0'+ch;ch=getchar();}
    14     return x*f;
    15 }
    16 int ksm(int a,int k){
    17     int res=1;
    18     while(k){
    19         if(k&1)res=(LL)res*a%mod;
    20         a=(LL)a*a%mod;
    21         k>>=1;
    22     }
    23     return res;
    24 }
    25 int fac[mxn*100],inv[mxn*100];
    26 void init(){
    27     int ed=mxn*100;
    28     fac[0]=fac[1]=1;inv[0]=inv[1]=1;
    29     for(int i=2;i<ed;i++){
    30         fac[i]=(LL)fac[i-1]*i%mod;
    31         inv[i]=((-mod/i*(LL)inv[mod%i]%mod)+mod)%mod;
    32     }
    33     return;
    34 }
    35 int C(int n,int m){
    36     if(m>n || n<0)return 0;
    37 //    return (LL)fac[n]*inv[m]%mod*inv[n-m]%mod;
    38     int res=1;
    39     for(int i=1;i<=m;i++){
    40         res=(LL)res*(n-m+i)%mod;
    41     }
    42     for(int i=1;i<=m;i++){
    43         res=(LL)res*ksm(i,mod-2)%mod;
    44     }
    45     return res;
    46 }
    47 int ans1,ans2,ans3;//1 2 0
    48 int n,smm,lower=0;
    49 int k1,k2,L[mxn],R[mxn];
    50 void calc(int pos,int f,int x){
    51     if(pos>n){
    52         ans1=((LL)ans1+f*C(smm-x+n-1,n))%mod;
    53 //        printf("%d %d
    ",smm-x+n-1,n);
    54         ans2=((LL)ans2+f*C(smm-x+n-1,n-1))%mod;
    55 //        printf("%d
    ",ans1);
    56         return;
    57     }
    58     calc(pos+1,-f,x+R[pos]-L[pos]+1);
    59     calc(pos+1,f,x);
    60     return;
    61 }
    62 int main(){
    63     int i,j;
    64 //    init();
    65     int T=read();
    66     while(T--){
    67         ans1=ans2=ans3=0;
    68         lower=1;smm=0;
    69         k1=read();
    70         for(i=1;i<=k1;i++){
    71             L[i]=read();R[i]=read();
    72             smm+=R[i];
    73         }
    74         k2=read();
    75         for(i=1;i<=k2;i++){
    76             L[i+k1]=read();R[i+k1]=read();
    77             smm-=L[i+k1];
    78         }
    79         n=k1+k2;
    80         for(i=1;i<=n;i++)lower=(LL)lower*(R[i]-L[i]+1)%mod;
    81         calc(1,1,0);
    82         int INV=ksm(lower,mod-2);
    83         ans3=((LL)lower-ans1-ans2)*INV%mod;
    84         ans1=(LL)ans1*INV%mod;
    85         ans2=(LL)ans2*INV%mod;
    86         ans1=(ans1+mod)%mod;
    87         ans2=(ans2+mod)%mod;
    88         ans3=(ans3+mod)%mod;
    89         printf("%d %d %d
    ",ans1,ans2,ans3);
    90     }
    91     return 0;
    92 }

    设前ki个集合为 $R_i - x_i$,后ki个集合为 $ L_i + x_i $此时x的取值范围是 $[0,R_i - L_i]$那么甲赢乙的情况需要满足的条件是:$$sum_{i=1}^{k_1} R_i-x_i > sum_{j=1}^{k_2} L_j+y_j $$$$sum_{i=1}^{k_1} x_i + sum_{j=1}^{k_2} y_j< sum_{i=1}^{k_1} R_i -sum_{j=1}^{k_2} L_j $$我们惊喜地发现右边是常数,那么可以用组合数+容斥算方程解的个数辣甲乙平手的情况,只需要把上面的大于换成等于号即可。乙赢甲的情况,可以把上式取负计算解个数,也可以直接用总方案数减去前两问方案数。总方案数当然就是所有的$R_i-L_i+1$的乘积

  • 相关阅读:
    斯坦福大学Andrew Ng教授主讲的《机器学习》公开课观后感
    关于内推,你该知道的点点滴滴
    向大学说拜拜——大学 > 兴趣 + 时间 + 思考 + 实践
    源码浅析:InnoDB聚集索引如何定位到数据的物理位置,并从磁盘读取
    5.7.17版本mysqlbinlog实时拉取的二进制日志不完整的原因分析
    InnoDB的ibd数据文件为什么比data_length+index_length+data_free的总和还要大?
    gh-ost工具在线改表过程的详细解析
    MySQL5.7 使用utf8mb4字符集比latin1字符集性能低25%,你敢信?
    通过slow query log可以查出长时间未提交的事务吗?用实验+源码来揭晓答案
    源码浅析:MySQL一条insert操作,会写哪些文件?包括UNDO相关的文件吗?
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/7057643.html
Copyright © 2011-2022 走看看