HDU 4790 2013 ACM/ICPC 成都赛区现场赛 J. Just Random

作者分享了解决HDU在线模拟现场赛中一道困难题目的经验,强调了处理细节和分类讨论的重要性。通过将区间左端平移至0并调整参数m,作者成功避免了模运算的复杂性。详细讨论了如何合并相似区间以减少时间复杂度,并提供了代码实现。文章展示了在紧张竞赛环境下保持冷静和深入理解问题的必要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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!




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值