HDU - 4790 Just Random (容斥定理+分析)

  Coach Pang and Uncle Yang both love numbers. Every morning they play a game with number together. In each game the following will be done:
  1. Coach Pang randomly choose a integer x in [a, b] with equal probability.
  2. Uncle Yang randomly choose a integer y in [c, d] with equal probability.
  3. If (x + y) mod p = m, they will go out and have a nice day together.
  4. Otherwise, they will do homework that day.
  For given a, b, c, d, p and m, Coach Pang wants to know the probability that they will go out.

Input

  The first line of the input contains an integer T denoting the number of test cases.
  For each test case, there is one line containing six integers a, b, c, d, p and m(0 <= a <= b <= 10 9, 0 <=c <= d <= 10 9, 0 <= m < p <= 10 9).

Output

  For each test case output a single line "Case #x: y". x is the case number and y is a fraction with numerator and denominator separated by a slash ('/') as the probability that they will go out. The fraction should be presented in the simplest form (with the smallest denominator), but always with a denominator (even if it is the unit).

Sample Input

4
0 5 0 5 3 0
0 999999 0 999999 1000000 0
0 3 0 3 8 7
3 3 4 4 7 0

Sample Output

Case #1: 1/3
Case #2: 1/1000000
Case #3: 0/1
Case #4: 1/1

设f(a,b)为(0<=x<=a,0<=y<=b)时的答案,由容斥定理可得

ans=f(b,d)-f(a-1,d)+f(a-1,c-1)-f(b,c-1)(前面为[a,b],[0,d],后面部分为-[a,b],[0,c-1]。)

首先是对p取余,那么区间的数都可以看成对p取余之后的数,那么两个区间就可以化为若干个[0,p-1]整区间和一个[0,?]的部分区间。问题就转为求取值范围分别为[0,p-1],[0,?]时解的个数,写写就可以知道不管m取多少,在[0,p-1]的任何一个数都可以找到一个也在[0,p-1]的数符合要求。也就是说两个[0,p-1]区间内,有p个答案。这里就可以分类求。

1.整区间:分别算出整区间的个数(numx,numy),那么整区间之间的贡献就是numx*numy*p。

2.部分区间:假设分别为[0,modx]、[0,mody],首先在每个整区间肯定都能找到相对应的数,所以贡献为(modx+1)*numy+(mody+1)*numx。剩下的就是[0,modx],[0,mody]这两个部分区间之间的贡献了。我们现在要找的是x+y=kp+m,因为0<=x,y<=p-1,0<=x+y<=2*p-2,所以k只能取0或1,即找x+y=m和x+y=p+m。我们可以只取x,然后在[0,mody]区间内找y=m-x和p+m-x即可。那么需要的y的取值范围就是[m-modx,m]和[p+m-modx,p+m],我们可以用mody分别与m和p+m取个最小值,然后再减去不需要(取不到)的部分即m-modx+1和p+m-modx+1(+1是因为m-modx和p+m-modx这两边界值需要取到。)

(参考博客:https://www.cnblogs.com/naturepengchen/articles/4081232.html

#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll a,b,c,d,p,m;
ll get(ll x,ll y)
{
	if(x<0||y<0) return 0;
	ll numx,numy,modx,mody,num1,num2;
	ll ans=0;
	numx=x/p,modx=x%p;//整数区间个数,部分区间[0,modx] 
	numy=y/p,mody=y%p;
	//cout<<numx<<" "<<modx<<endl;
	//cout<<numy<<" "<<mody<<endl;
	//和整数区间有关的所有贡献 
	ans=numx*numy*p+(modx+1)*numy+(mody+1)*numx;
	//和部分区间之间的贡献 
	num1=max(0LL,min(mody,m)-max(m-modx,0LL)+1);
	num2=max(0LL,min(mody,p+m)-max(p+m-modx,0LL)+1);
	ans+=(num1+num2);
	return ans;
	
}
int main(void)
{
	int t,tt=0;
	
	scanf("%d",&t);
	
	while(t--)
	{
		scanf("%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&p,&m);
		ll ans=get(b,d)-get(a-1,d)+get(a-1,c-1)-get(b,c-1);
		ll down=(b-a+1)*(d-c+1);
		ll g=__gcd(ans,down);
		ans/=g; down/=g;
		printf("Case #%d: %lld/%lld\n",++tt,ans,down);
	}
	
	
	return 0;	
} 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值