题目链接
题目描述
给定初始映射 f: [0, 2^64) → [0, 2^64)
,对任意 x
初始 f(x) = 0
。
共有 n
次操作,对于第 i
次操作(从 1 到 n
),会给定一对整数 (x, y)
,执行:
- 记录
ans_i = f(x)
的当前值。 - 更新映射:
f(x) = y
。
要求计算最终的总和:
这是一个 ACM 模式 的题目,你需要处理标准输入和输出。
输入描述:
第一行包含一个整数 n
()。
接下来的
n
行,每行包含两个整数 x, y
()。
输出描述:
输出一个整数,表示 的结果。
示例: 输入:
3
1 5
2 4
1 7
输出:
15
说明:
- 第1次 (i=1): 操作
(1, 5)
。ans_1 = f(1)
,初始为0
。总和+= 1 * 0
。更新f(1) = 5
。 - 第2次 (i=2): 操作
(2, 4)
。ans_2 = f(2)
,初始为0
。总和+= 2 * 0
。更新f(2) = 4
。 - 第3次 (i=3): 操作
(1, 7)
。ans_3 = f(1)
,当前为5
。总和+= 3 * 5
。更新f(1) = 7
。 - 最终总和 =
0 + 0 + 15 = 15
。
解题思路
这道题的核心是模拟一个可以动态更新的函数 f
,并累加一个带权重的和。关键点在于处理巨大的数据范围。
x
和 y
的范围达到了 [0, 2^64)
,这意味着我们必须使用64位无符号整数来存储它们。普通32位 int
会导致数据溢出。
最适合的数据结构是 哈希表(在 C++ 中是 unordered_map
,Java 中是 HashMap
,Python 中是 dict
)。
算法步骤:
- 初始化一个哈希表
f_map
,键和值的类型都应为64位整型。 - 初始化一个64位整型变量
total_sum = 0
。 - 读取操作次数
n
。 - 使用一个循环,从
i = 1
迭代到n
: a. 读取当次操作的64位整数x
和y
。 b. 查询f(x)
: 在f_map
中查找键x
。如果不存在,其值默认为0
。 c. 累加总和: 计算i * f(x)
并加到total_sum
上。 d. 更新映射: 在f_map
中设置f_map[x] = y
。 - 循环结束后,输出
total_sum
。
语言实现细节:
- C++: 使用
unsigned long long
类型。该类型的算术运算在溢出时会自动对2^64
取模,这正是题目要求。 - Java:
long
类型是64位有符号整数,无法存储大于的输入值
x
和y
。此外,中间的累加和totalSum
也会远超long
的范围。因此,必须使用java.math.BigInteger
类,它可以处理任意大小的整数。最后使用.mod()
方法进行取模。 - Python: Python 的
int
类型支持任意精度,不会溢出。因此,我们需要在计算总和后,手动对2**64
进行取模操作。
代码
#include <iostream>
#include <unordered_map>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin >> n;
unordered_map<unsigned long long, unsigned long long> f_map;
unsigned long long total_sum = 0;
for (unsigned long long i = 1; i <= n; ++i) {
unsigned long long x, y;
cin >> x >> y;
unsigned long long ans_i = 0;
if (f_map.count(x)) {
ans_i = f_map[x];
}
total_sum += i * ans_i;
f_map[x] = y;
}
cout << total_sum << endl;
return 0;
}
import java.util.Scanner;
import java.util.HashMap;
import java.util.Map;
import java.math.BigInteger;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
Map<BigInteger, BigInteger> fMap = new HashMap<>();
BigInteger totalSum = BigInteger.ZERO;
for (int i = 1; i <= n; i++) {
BigInteger x = sc.nextBigInteger();
BigInteger y = sc.nextBigInteger();
BigInteger ansI = fMap.getOrDefault(x, BigInteger.ZERO);
BigInteger iBig = BigInteger.valueOf(i);
totalSum = totalSum.add(iBig.multiply(ansI));
fMap.put(x, y);
}
BigInteger modVal = BigInteger.valueOf(2).pow(64);
System.out.println(totalSum.mod(modVal));
}
}
n = int(input())
f_map = {}
total_sum = 0
for i in range(1, n + 1):
x, y = map(int, input().split())
ans_i = f_map.get(x, 0)
total_sum += i * ans_i
f_map[x] = y
# 对 2^64 取模,使用位运算 & (2^64 - 1) 效率更高且结果正确
print(total_sum & ((1 << 64) - 1))
算法及复杂度
- 算法: 哈希表
- 时间复杂度:
。每次操作都对应一次哈希表的查找和一次插入/更新,这些操作的平均时间复杂度都是
。因此总时间复杂度与操作次数
N
成正比。 - 空间复杂度:
,其中
U
是在所有操作中遇到的不同x
的数量。在最坏情况下,每次操作的x
都不同,此时U
等于N
,空间复杂度为。