首页 > 代码库 > HDU - 4790 Just Random

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;
}