数学-HDU4790

来源:互联网 发布:遇到网络诈骗怎么报警 编辑:程序博客网 时间:2024/04/29 18:16

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4790

题目意思是:从区间[a,b]选取一个数字x,区间[c,d]选取一个数字y,使得(x+y)%p=m。问你几率有多大。最简分式输出(除gcd就可以)。
总的事件总数就是(b-a+1)*(d-c+1)。

关键是求 满足(x+y)%p=m 的选择方法总数。
如何求呢?

其实直接求不好求,而且容易超时。
我们可以先利用容斥原理转化一下。
假定f(a,b)表示的是在区间0~a和区间0~b中分别取x和y使得(x+y)%p=m的事件数。
那么ans=f(b,d)-f(b,c-1)-f(a-1,d)+f(a-1,c-1)。(f(a-1,c-1)是被减了两遍的)。
那如何求f(a,b)呢,其实这是关键。

下面我引用一个博客的例子:
例如:求f(16,8),p=6,m=2.
因为(x+y)%p=(x%p+y%p)%p.所以重写一下0~a和0~b两个区间。
对于a有:0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4
对于b有:0 1 2 3 4 5 0 1 2
a中(0 1 2 3 4 5)的数量为 a/p个,b中(0 1 2 3 4 5)的数量为 b/p个。
所以根据这个将两个区间分为四部分。
这样取A集合为(0 1 2 3 4 5/0 1 2 3 4 5),B集合为(0 1 2 3 4)
C集合为(0 1 2 3 4 5/),D集合为(0 1 2)。
这样就可以分成4部分来计算了。
f(16,7)=A和C满足条件的数+A和D满足条件的数+B和C满足条件的数+B和D满足条件的数。

一、A和C满足条件的数:
A中先取一个其中一个(0 1 2 3 4 5),C中取一个(0 1 2 3 4 5)从A中取一个数x,C中任意一个数y相加对p取余的范围是[0~5]也就是说 一个x对应一个y,A中有a/p个(0 1 2 3 4 5)C中有b/p个(0 1 2 3 4 5)每个区间p个数,所以总数为ans=(a/p)*(b/p)*p.

二、A和D满足条件的数:
D集合中元素数目mb=b%p+1(元素0)。根据( 一、),AD满足的条件数为ans+=mb*(a/p)。

三、B和C满足条件的数:
跟(二、)同理,为ans+=(a%p+1)*(b/p)。

四、B和D满足条件的数:
最难求的就是这个啦,难求在哪呢,或者说跟前面的区别在哪呢。
因为B或D中任意一元素并不一定在另一个集合中有对应,例如B中 (3,4,5)在D中都没有对应。所以我们这样分情况:

(1)ma>m:(B集合元素:0,1,2……m……ma)
ma大于m就意味着集合D中最多有m+1个元素(元素0)跟他相对应,为什么最多呢,因为D集合中元素个数可能小于m+1。所以ans+=min(m,mb)+1。这是所有情况吗?其实不是,当(mb+ma)%p>=m时就会漏掉一些情况。D集合中最大元素为mb,B中最大为ma,令t=(m-ma+p)%p(如果mb小于m那么t>mb?)。这是求出来的满足B中最大项在D对应的值,如果t<=mb那就说明D中有mb-t+1个元素(区间t~mb)与之相对应。ans+=mb-t+1。

(2)ma<=m:(B集合元素:0,1…ma)
ma<=m时,D集合中最多有ma个元素跟他相对应啦。所以跟(1)后半部分相似。D集合中最大元素为mb,B中最大为ma,同样令t=(m-ma+p)%p。也就是ma对应的D集合中最大值。如果t<=mb那就说明D中有元素跟他对应。 假设有k个,首先B集合中肯定有0没0就说明B集合没有元素。D中跟0相对应的是m,所以元素个数不会超过k=m-t+1个。mb可能小于m吧,这个之前并没有讨论。所以k也不会超过mb-t+1个。ans+=min(mb-t+1,m-t+1)。
至此,所有情况就讨论完了。
代码:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <map>#define ll long longusing namespace std;ll p,m;ll g(ll x,ll y){    if(x<y)swap(x,y);    if(!y)return x;    else return g(y,x%y);}ll f(ll x,ll y){    if(x<0||y<0)return 0;    ll ans=(x/p)*(y/p)*p;    ll mx=x%p,my=y%p;    ans+=(y/p)*(mx+1);    ans+=(my+1)*(x/p);    if(mx>m)    {        ans+=min(m,my)+1;        ll t=(m-mx+p)%p;        if(t<=my)ans+=my-t+1;    }    else    {        ll t=(p+m-mx)%p;        if(t<=my)ans+=min(m-t+1,my-t+1);    }    return ans;}int main(){    ll a,b,c,d;    int T;    scanf("%d",&T);    int ca=1;    while(T--)    {        ll sum;        scanf("%I64d %I64d %I64d %I64d %I64d %I64d",&a,&b,&c,&d,&p,&m);        ll ss=f(b,d)-f(a-1,d)-f(b,c-1)+f(a-1,c-1);        sum=(b-a+1)*(d-c+1);        ll gcd=g(sum,ss);        sum=sum/gcd;        ss=ss/gcd;        printf("Case #%d: %I64d/%I64d\n",ca++,ss,sum);    }}
原创粉丝点击