hdu上模拟现场赛,做这题的时候很快出了想法,但是就是写错,一直wa, 不过再调试过程中应该算把这题理解地非常透彻了,感觉如果标解是和我思路一样的话,这题的难点就是细节处理,详细的分类讨论。其实后来想明白了以后分类也很清晰自然了,感觉现场老是紧张有点想不清楚,但是还是硬着头皮写,ym那些现场怒A这题的大神。
下面说下我的思路: 对于题目给的区间,[a, b], [c, d],区间的端点模p的值不够连续是很不爽的,比如[a, b] = [11, 100], p = 7, 也就是说 [11, 100]区间里的数模7是这样分布的: 4 5 6 0 1 2 3 4 5 6 0 1 2 3 4 5 6 ......0 1 2 3 4 5 6 0 1 2,这显然对后面统计每种剩余系的元素个数造成巨大不便,所以我当时就想把这种情况避免掉,然后一个想法自然产生:把区间左端都移到0,为了平移以后和原题等价,我们只需把 m 的值也同时减小, 设想一下 求 [11, 100]里的数 加上 [c, d]区间里的一个数 模7 余5 和求 [10, 99]里的数加上 [c, d]区间里的一个数 模7 余4的个数是一样的吧。(证明很简单,原来 x + y == 5, 11 <= x <=100, 那么 x - 1 + y == 4,10 <= x - 1 <= 99,所以结论显然), 所以我们可以把两个区间变成 [0, b - a], [0, d - c], m 变成 ((m - a - c) % p + p) % p (使m>= 0).
然后为了不TLE,显然我们要把一些范围内的数一起算。举个例子 平移好了之后是[0, 11], [0, 13], m = 4, p = 7, 那么第一个区间模7为0 -- 4 的都有2个, 5--6的有1个,后一个区间模7 为0--6的都是2个,所以如果前一个区间取得是0,1,2,或3,那么后一个区间可以取3, 2, 1, 0,这几个数可以一起算,其他类似不多说。按这样讨论,如果x取的是[0, m]之间的数,那么y对应要取[m, 0],如果x取得是[m + 1, p - 1],那么y要取[p - 1,m + 1]。
然后剩下的就是详细的讨论了。我就不多说了。贴代码:(想清楚以后讨论其实不难)
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cctype>
#include <bitset>
#include <ctime>
#include <set>
#include <list>
#include <stack>
#include <queue>
#include <deque>
#include <string>
#include <vector>
#include <map>
#pragma warning (disable : 4996)
#define mem(a) memset(a, 0, sizeof(a))
#define dou double
#define LL long long
#define N 111111
#define Mod 1000000007
#define sl(a) strlen(a)
#define eps 1e-8
#define inf 2000000000
using namespace std;
LL gcd(LL a, LL b){
return b ? gcd(b, a % b) : a;
}
int main(){
LL n, t, ca = 1, i, j, k, cnt, re, a, b, c, d, m, p, x, y, bb, dd, cb1, cb2, cd1, cd2;
//freopen("in,txt", "r", stdin);
//freopen("myout.txt", "w", stdout);
//ios :: sync_with_stdio(false);
scanf("%I64d", &t);
while (t--){
scanf("%I64d%I64d%I64d%I64d%I64d%I64d", &a, &b, &c, &d, &p, &m);
m -= (a + c); m %= p; m = (m + p) % p;
b -= a, d -= c, bb = b % p, dd = d % p;
y = (b + 1) * (d + 1);
cb1 = (b - bb) / p + 1, cb2 = cb1 - 1;
cd1 = (d - dd) / p + 1, cd2 = cd1 - 1;
x = 0;
if (m > bb){
if (m <= dd) x += cb1 * cd1 * (bb + 1);
else if (m - bb > dd) x += cb1 * cd2 * (bb + 1);
else x += cb1 * cd1 * (dd - m + bb + 1) + cb1 * cd2 * (m - dd);
if (m - bb - 1 <= dd) x += cb2 * cd1 * (m - bb);
else x += cb2 * cd1 * (dd + 1) + cb2 * cd2 * (m - bb - 1 - dd);
if (m + 1 > dd) x += cb2 * cd2 * (p - m - 1);
else x += cb2 * cd1 * (dd - m) + cb2 * cd2 * (p - 1 - dd);
}
else if (m == bb){
if (m <= dd) x += cb1 * cd1 * (bb + 1);
else x += cb1 * cd1 * (dd + 1) + cb1 * cd2 * (m - dd);
if (m + 1 > dd) x += cb2 * cd2 * (p - m - 1);
else x += cb2 * cd1 * (dd - m) + cb2 * cd2 * (p - 1 - dd);
}
else {
if (m <= dd) x += cb1 * cd1 * (m + 1);
else x += cb1 * cd1 * (dd + 1) + cb1 * cd2 * (m - dd);
if (p + m - bb > dd) x += cb1 * cd2 * (bb - m);
else x += cb1 * cd1 * (dd - p - m + bb + 1) + cb1 * cd2 * (p - 1 - dd);
if (m + 1 > dd) x += cb2 * cd2 * (p - bb - 1);
else if (p + m - bb - 1 <= dd) x += cb2 * cd1 * (p - bb - 1);
else x += cb2 * cd1 * (dd - m) + cb2 * cd2 * (p + m - bb - 1 - dd);
}
a = gcd(x, y);
printf("Case #%I64d: %I64d/%I64d\n", ca++, x / a, y / a);
}
return 0;
}
AC!