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