HDU - 4790 Just Random

题意:求从[a,b],[c,d]两个区间找到两个数使得他们的和%p=m,求概率

思路:我们想办法把区间的左范围化到0,那么结果就相对好弄了,应用容斥原理比直接解答问题简单点,假设f(a,b)是区间[0,a],[0,b]中满足条件的个数,设p=6.m=2

那么第一个区间可以看成 : 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)

那么题目就可以看成:A+C,A+D, B+D ,C+D的结果和

前三个不难算,关键是第四个:根据与m的大小做对比,假设B最大的是ma,D最大的是mb

那么当ma>m的时候,我们可以尝试从mb的范围里找是否有能与ma中小于m的数中结合成m,还有的情况是从mb中找一个使得他们和大于p且%p=m;另一种情况就相对简单点了,具体的还有差别,动手模拟一下

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define ll long long

ll a,b,c,d,p,m;

ll gcd(ll a, ll b){
	if (b == 0)	
		return a;
	return gcd(b,a%b);
}

ll f(ll a, ll b){
	if (a < 0 || b < 0)
		return 0;
	ll ma = a%p, mb = b%p;
	ll ans = (a/p)*(b/p)*p;
	ans += (ma+1)*(b/p) + (mb+1)*(a/p);
	if (ma > m){
		ans += min(m, mb) + 1;
		ll t = (p+m-ma) % p;
		if (t <= mb)
			ans +=  mb-t+1;
	}
	else {
		ll t = (p+m-ma)%p;
		if (t <= mb)
			ans += min(m-t+1, mb-t+1);
	}
	return ans;
}

int main(){
	int cas = 1,t;
	scanf("%d", &t);
	while (t--){
		scanf("%lld%lld%lld%lld%lld%lld", &a, &b, &c, &d, &p, &m);
		ll ans = f(b, d)-f(b, c-1)-f(a-1, d)+f(a-1, c-1);
		ll tot = (b-a+1)*(d-c+1);
		ll g = gcd(ans, tot);
		printf("Case #%d: ", cas++);
		cout << ans/g << "/" << tot/g << endl;
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值