题意很简单,给出两个区间[a, b], [c, d]
在给出两个整数p, m
问你这两个区间各取一个数字使其和模p为m
这样的数占所有情况的比例
这个题学长说的思路,我敲的代码,真的给我搞的元气大伤!!
因为区间内的数是连续的,所以我们可以推知对于所有情况的集合S
可以把S分为3段,左侧一段从1递增,中间一段保持不变,右侧一段递减至1
接着就一步一步推,处理就好了
还是自己太弱,写了接近4个小时
代码如下(完美注释。。。):
#include <cstdio>
#include <iostream>
#include <algorithm>
#define LL unsigned long long
using namespace std;
LL gcd(LL a, LL b) {
return b ? gcd(b, a%b) : a;
}
int main(void) {
int T, a, b, c, d, p, m;
LL l_left, m_left, r_left, tmp;
LL l_right, m_right, r_right;
LL l_first, l_last, l_cnt, l_sum;
LL m_first, m_last, m_cnt, m_sum;
LL r_first, r_last, r_cnt, r_sum;
scanf("%d", &T);
for(int _=1; _<=T; ++_) {
scanf("%d%d%d%d%d%d", &a, &b, &c, &d, &p, &m);
l_left = a+c; l_right = a+c+min(b-a, d-c)-1;
m_left = l_right+1; m_right = b+d-min(b-a, d-c);
r_left = m_right+1; r_right = b+d;
/*
printf("左边界: %lld -- %lld\n", l_left, l_right);
printf("中间边界: %lld -- %lld\n", m_left, m_right);
printf("右边界: %lld -- %lld\n", r_left, r_right);
puts("");puts("");puts("");puts("");
*/
l_first = l_last = -1;
tmp = l_left+(m-l_left%p);
if(m >= l_left%p)
l_first = tmp;//左侧等差数列第一项
else l_first = tmp+p;
if(l_first > l_right || l_first < l_left)
l_first = -1;
tmp = l_right-(l_right%p-m);
if(m <= l_right%p)
l_last = tmp;//左侧等差数列最后一项
else l_last = tmp-p;
if(l_last < l_left || l_last > l_right)
l_last = -1;
if(l_first==-1 && l_last==-1) {
l_cnt = 0;
l_sum = 0;
} else if(l_first == -1) {
l_cnt = 1;
l_sum = l_last-l_left+1;
} else if(l_last == -1) {
l_cnt = 1;
l_sum = l_first-l_left+1;
} else {
l_cnt = (l_last-l_first)/p+1;//左侧符合条件的项数
l_sum = ((l_first-l_left+1) + (l_last-l_left+1))*l_cnt>>1;
}
/*
printf("左侧等差数列满足条件边界:%lld -- %lld\n", l_first, l_last);
printf("左侧的个数和结果:%lld -- %lld\n", l_cnt, l_sum);
puts("");puts("");puts("");puts("");
*/
m_first = m_last = -1;
tmp = m_left+(m-m_left%p);
if(m >= m_left%p)
m_first = tmp;
else m_first = tmp+p;
if(m_first > m_right || m_first < m_left)
m_first = -1;
tmp = m_right-(m_right%p-m);
if(m <= m_right%p)
m_last = tmp;
else m_last = tmp-p;
if(m_last < m_left || m_last > m_right)
m_last = -1;
if(m_last==-1 && m_first==-1) {
m_cnt = 0;
m_sum = 0;
} else if(m_first == -1) {
m_cnt = 1;
m_sum = m_left-l_left+1;
} else if(m_last == -1) {
m_cnt = 1;
m_sum = m_left-l_left+1;
} else {
m_cnt = (m_last-m_first)/p+1;
m_sum = m_cnt*(m_left-l_left+1);
}
/*
printf("中间等差数列满足条件边界:%lld -- %lld\n", m_first, m_last);
printf("中间的个数和结果:%lld -- %lld\n", m_cnt, m_sum);
puts("");puts("");puts("");puts("");
*/
r_first = r_last = -1;
tmp = r_left+(m-r_left%p);
if(m >= r_left%p)
r_first = tmp;
else r_first = tmp+p;
if(r_first > r_right || r_first < r_left)
r_first = -1;
tmp = r_right-(r_right%p-m);
if(m <= r_right%p)
r_last = tmp;
else r_last = tmp-p;
if(r_last < r_left || r_last > r_right)
r_last = -1;
if(r_last==-1 && r_first==-1) {
r_cnt = 0;
r_sum = 0;
} else if(r_first==-1 && r_last!=-1) {
r_cnt = 1;
r_sum = (r_right-r_last+1);
} else if(r_last == -1 && r_first!=-1) {
r_cnt = 1;
r_sum = (r_right-r_first+1);
} else {
r_cnt = (r_last-r_first)/p+1;
r_sum = r_cnt*((r_right-r_first+1) + (r_right-r_last+1))>>1;
}
/*
printf("右侧等差数列满足条件边界:%lld -- %lld\n", r_first, r_last);
printf("右侧的个数和结果:%lld -- %lld\n", r_cnt, r_sum);
puts("");puts("");puts("");puts("");
*/
LL ans1 = l_sum+m_sum+r_sum;
LL ans2 = (LL)(b-a+1)*(d-c+1);
LL g = gcd(ans1, ans2);
if(g) {
ans1 /= g;
ans2 /= g;
}
if(ans1 == 0)
ans2 = 1;
printf("Case #%d: ", _);
cout << ans1 << "/" << ans2 << endl;
}
return 0;
}