1 条题解

  • 0
    @ 2025-11-12 18:14:44

    题目分析:

    这是一个关于玩家经验值增长的数学建模问题。n个玩家有不同的初始经验值,每回合每个玩家的经验值会增加,增加量等于其他玩家中经验值严格大于该玩家的不同经验值数量。

    关键洞察

    1. 增长规则:每个玩家每回合增加的经验值 = 严格大于其当前经验值的不同经验值数量
    2. 等级合并:经验值较低的玩家增长较快,最终所有玩家经验值会趋于相同
    3. 数学规律:经过有限回合后,系统会达到稳定状态

    算法策略

    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. 分组思想:将相同经验值的玩家合并处理
    2. 合并时间:精确计算等级合并的临界点
    3. 连锁反应:正确处理多个等级连续合并的情况
    4. 数学优化:避免模拟每个回合,直接计算公式

    这个解法能够高效处理大规模数据,并通过数学分析直接计算任意回合后的状态。

    • 1

    信息

    ID
    5288
    时间
    1000ms
    内存
    256MiB
    难度
    9
    标签
    递交数
    7
    已通过
    1
    上传者