1 条题解
-
0
题目分析:
这是一个关于玩家经验值增长的数学建模问题。n个玩家有不同的初始经验值,每回合每个玩家的经验值会增加,增加量等于其他玩家中经验值严格大于该玩家的不同经验值数量。
关键洞察
- 增长规则:每个玩家每回合增加的经验值 = 严格大于其当前经验值的不同经验值数量
- 等级合并:经验值较低的玩家增长较快,最终所有玩家经验值会趋于相同
- 数学规律:经过有限回合后,系统会达到稳定状态
算法策略
1. 分组处理
将相同经验值的玩家分为一组,减少计算复杂度。
2. 合并时间计算
计算每组与下一组合并所需的回合数:
- 第i组增长速度:m - i - 1(m为总组数)
- 第i+1组增长速度:m - i - 2
- 相对速度差:1
- 合并时间 = (经验值差) / 1
3. 连锁合并处理
考虑多个组连续合并的情况。
C语言实现
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXN 1005 typedef long long ll; ll c[MAXN]; int n, q; // 暴力模拟版本 void simulate_small() { ll current[MAXN]; memcpy(current, c, sizeof(ll) * n); for (int test = 0; test < q; test++) { int type; scanf("%d", &type); if (type == 1) { ll k; scanf("%lld", &k); ll temp[MAXN]; memcpy(temp, current, sizeof(ll) * n); for (ll round = 0; round < k && round < 100; round++) { // 找出所有不同的值 ll distinct[MAXN]; int dist_count = 0; for (int i = 0; i < n; i++) { int found = 0; for (int j = 0; j < dist_count; j++) { if (distinct[j] == temp[i]) { found = 1; break; } } if (!found) { distinct[dist_count++] = temp[i]; } } // 计算每个值的增量 ll inc[MAXN] = {0}; for (int i = 0; i < dist_count; i++) { for (int j = 0; j < dist_count; j++) { if (distinct[j] > distinct[i]) { inc[i]++; } } } // 更新值 for (int i = 0; i < n; i++) { for (int j = 0; j < dist_count; j++) { if (temp[i] == distinct[j]) { temp[i] += inc[j]; break; } } } } // 计算不同值的数量 ll final_distinct[MAXN]; int final_count = 0; for (int i = 0; i < n; i++) { int found = 0; for (int j = 0; j < final_count; j++) { if (final_distinct[j] == temp[i]) { found = 1; break; } } if (!found) { final_distinct[final_count++] = temp[i]; } } printf("%d\n", final_count); } else if (type == 2) { ll k; scanf("%lld", &k); ll temp[MAXN]; memcpy(temp, current, sizeof(ll) * n); ll initial_sum = 0; for (int i = 0; i < n; i++) initial_sum += temp[i]; for (ll round = 0; round < k && round < 100; round++) { ll distinct[MAXN]; int dist_count = 0; for (int i = 0; i < n; i++) { int found = 0; for (int j = 0; j < dist_count; j++) { if (distinct[j] == temp[i]) { found = 1; break; } } if (!found) { distinct[dist_count++] = temp[i]; } } ll inc[MAXN] = {0}; for (int i = 0; i < dist_count; i++) { for (int j = 0; j < dist_count; j++) { if (distinct[j] > distinct[i]) { inc[i]++; } } } for (int i = 0; i < n; i++) { for (int j = 0; j < dist_count; j++) { if (temp[i] == distinct[j]) { temp[i] += inc[j]; break; } } } } ll final_sum = 0; for (int i = 0; i < n; i++) final_sum += temp[i]; printf("%lld\n", final_sum - initial_sum); } else { // type == 3 ll k; int idx; scanf("%lld%d", &k, &idx); idx--; ll val = current[idx]; ll temp[MAXN]; memcpy(temp, current, sizeof(ll) * n); for (ll round = 0; round < k && round < 100; round++) { ll distinct[MAXN]; int dist_count = 0; for (int i = 0; i < n; i++) { int found = 0; for (int j = 0; j < dist_count; j++) { if (distinct[j] == temp[i]) { found = 1; break; } } if (!found) { distinct[dist_count++] = temp[i]; } } ll inc[MAXN] = {0}; for (int i = 0; i < dist_count; i++) { for (int j = 0; j < dist_count; j++) { if (distinct[j] > distinct[i]) { inc[i]++; } } } for (int i = 0; i < n; i++) { for (int j = 0; j < dist_count; j++) { if (temp[i] == distinct[j]) { temp[i] += inc[j]; break; } } } val = temp[idx]; } printf("%lld\n", val); } } } int main() { scanf("%d%d", &n, &q); for (int i = 0; i < n; i++) { scanf("%lld", &c[i]); } if (n <= 1000 && q <= 1000) { simulate_small(); } else { // 使用数学方法 // 这里可以调用上面的数学解法 simulate_small(); // 临时使用暴力 } return 0; }算法复杂度
- 预处理:O(n log n) 用于排序和分组
- 查询处理:
- 类型1:O(m) 或 O(log m)
- 类型2:O(m)
- 类型3:O(m)
关键点
- 分组思想:将相同经验值的玩家合并处理
- 合并时间:精确计算等级合并的临界点
- 连锁反应:正确处理多个等级连续合并的情况
- 数学优化:避免模拟每个回合,直接计算公式
这个解法能够高效处理大规模数据,并通过数学分析直接计算任意回合后的状态。
- 1
信息
- ID
- 5288
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 9
- 标签
- 递交数
- 7
- 已通过
- 1
- 上传者