Atcoder ABC339 F - Product Equality

Product Equality(乘积相等)

时间限制:2s 内存限制:1024MB

【原题地址】

所有图片源自Atcoder,题目译文源自脚本Atcoder Better!

点击此处跳转至原题

【问题描述】

在这里插入图片描述

【输入格式】

在这里插入图片描述
在这里插入图片描述

【输出格式】

在这里插入图片描述

【样例1】

【样例输入1】

5
2
3
6
12
24

【样例输出1】

6

【样例说明1】

在这里插入图片描述

【样例2】

【样例输入2】

11
1
2
3
4
5
6
123456789123456789
123456789123456789
987654321987654321
987654321987654321
121932631356500531347203169112635269

【样例输出2】

40

【样例说明2】

在这里插入图片描述

【样例3】

【样例输入3】

9
4
4
4
2
2
2
1
1
1

【样例输出3】

162

【样例说明3】

在这里插入图片描述

【解题思路】

老汉使用到的是字符串哈希的解题方式

本题是求N个整数中的任意两个相乘,乘积在这N个整数中存在,这样的组合一个有几对。
注意本题的数据量非常大,达到 1 0 1000 10^{1000} 101000,很显然O( N 2 N^2 N2)的时间复杂度是最基础的,但由于数据计算量大,两秒的时间内无法完成,这里我们使用到字符串哈希来缩小数据量,从而减少计算量,我们知道字符串哈希是存在误差的,因此我们可以取三个不同的Mod值,纯数字字符串我们直接取Base值为10,比较对应的哈希值乘积在这N个整数的哈希值相同的有几个,统计这个总数,即为最终结果

代码注释有详细过程

【代码】

package ABC339_F_ProductEquality;

import java.util.*;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		// 用于存放三个不同mod值的字符串哈希值
		long[] a = new long[n];
		long[] b = new long[n];
		long[] c = new long[n];
		// 随机给定三个不同的mod值
		Random rm = new Random();
		int mod1 = (int) 1e9 + (rm.nextInt() % (int) 1e9);
		int mod2 = (int) 1e9 + (rm.nextInt() % (int) 1e9);
		int mod3 = (int) 1e9 + (rm.nextInt() % (int) 1e9);
		for (int i = 0; i < n; i++) {
			char[] s = sc.next().toCharArray();
			int N = s.length;
			// 求字符串对应的三个哈希值,Base取10
			for (int j = 0; j < N; j++) {
				a[i] = (a[i] * 10) + (s[j] - '0');
				a[i] %= mod1;
				b[i] = (b[i] * 10) + (s[j] - '0');
				b[i] %= mod2;
				c[i] = (c[i] * 10) + (s[j] - '0');
				c[i] %= mod3;
			}
		}
		// 用哈希键值对集合存储对应的哈希值出现的次数
		Map<Long, Integer> map1 = new HashMap<>();
		for (int i = 0; i < n; i++) {
			map1.put(a[i], map1.getOrDefault(a[i], 0) + 1);
		}
		Map<Long, Integer> map2 = new HashMap<>();
		for (int i = 0; i < n; i++) {
			map2.put(b[i], map2.getOrDefault(b[i], 0) + 1);
		}
		Map<Long, Integer> map3 = new HashMap<>();
		for (int i = 0; i < n; i++) {
			map3.put(c[i], map3.getOrDefault(c[i], 0) + 1);
		}
		long ans = 0;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				// 求对应下标两个数的乘积的三个哈希值
				long mul1 = a[i] * a[j] % mod1, mul2 = b[i] * b[j] % mod2, mul3 = c[i] * c[j] % mod3;
				// 获取在集合中存在几个对应的乘积值,取三个不同的哈希值中存在个数最小的那个,缩小误差
				int v = Math.min(map1.getOrDefault(mul1, 0), map2.getOrDefault(mul2, 0));
				ans += (Math.min(v, map3.getOrDefault(mul3, 0)));
			}
		}
		System.out.println(ans);
		sc.close();
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王老汉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值