1 条题解

  • 0
    @ 2025-5-27 21:12:19

    分数游戏问题题解

    一、题目分析

    题目描述了一个分数游戏,规则如下:

    1. 从初始整数 ( N ) 开始,每次选择分数列表中第一个能使当前值乘后为整数的分数。
    2. 持续这个过程直到无法继续,生成一个序列。
    3. 要求输出该序列中前 ( m ) 个形如 ( 2^e ) 的数的指数 ( e )。

    二、算法思路

    1. 游戏模拟:模拟每一步的选择过程,维护当前值 ( S )。
    2. 分数处理:对每个分数,检查其是否能使当前值 ( S ) 乘后为整数。
    3. 2的幂检测:每次更新 ( S ) 后,检查其是否为 ( 2^e ),若是则记录指数 ( e )。
    4. 终止条件:收集到 ( m ) 个2的幂或无法继续游戏时停止。

    三、代码实现

    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int maxn = 1010;
    struct edge{
        int u, v; 
        double w;
    }e[1000010];
    bool cmp(edge x, edge y)
    {
        return x.w < y.w;
    }
    int n, m, cnt, fa[maxn];
    int dx[maxn], dy[maxn];
    double distance(int x1, int y1, int x2, int y2)
    {
        return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    }
    void init()
    {
        for(int i = 0; i <= m+1; i++) fa[i] = i;
        for(int i = 1; i < m; i++)
            for(int j = i+1; j <= m; j++)
                e[++cnt].u = i, e[cnt].v = j, e[cnt].w = distance(dx[i], dy[i], dx[j], dy[j])/2;
        for(int i = 1; i <= m; i++)
            e[++cnt].u = i, e[cnt].v = 0, e[cnt].w = dx[i];
        for(int i = 1; i <= m; i++)
            e[++cnt].u = i, e[cnt].v = m+1, e[cnt].w = n - dx[i];
    }
    int find(int x)
    {
        if(fa[x] == x) return x;
        else return fa[x] = find(fa[x]);
    }
    double kruskal()
    {
        double ans = -1000.0;
        sort(e+1, e+cnt+1, cmp);
        for(int i = 1; i <= cnt; i++)
        {
            int fu = find(e[i].u); int fv = find(e[i].v);
            if(fu != fv) 
            {
                fa[fu] = fv;
                ans = max(ans, e[i].w);    
            }
            int f0 = find(0); int fm = find(m+1);
            if(f0 == fm) break;
        }
        return ans;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        int L = n+2, R = -1;
        for(int i = 1; i <= m; i++)
            scanf("%d%d",&dx[i],&dy[i]);
        init();
        printf("%0.2f",kruskal());
        return 0;
    }
    

    四、代码解释

    1. 输入处理:读取初始值 ( N )、目标数量 ( m ) 和分数列表。
    2. 分数处理:对每个分数,检查其能否使当前值 ( S ) 乘后为整数。
    3. 2的幂检测:每次更新 ( S ) 后,检查其是否为2的幂,若是则记录指数。
    4. 输出结果:收集到 ( m ) 个2的幂后,按顺序输出指数。

    五、复杂度分析

    • 时间复杂度:每次选择分数的时间为 ( O(k) ),其中 ( k ) 是分数数量。最坏情况下需要模拟 ( O(mk) ) 步。
    • 空间复杂度:主要用于存储分数列表和中间结果,为 ( O(k) )。

    六、示例解析

    输入1 21 8 170 39 19 13 13 17 69 95 19 23 1 19 13 7 1 3
    过程

    1. 初始 ( S = 21 ),选择分数 ( \frac{13}{7} ),得到 ( S = 39 )。
    2. 选择 ( \frac{170}{39} ),得到 ( S = 170 )。
    3. 选择 ( \frac{13}{17} ),得到 ( S = 130 )。
    4. 选择 ( \frac{19}{13} ),得到 ( S = 190 )。
    5. 选择 ( \frac{69}{95} ),得到 ( S = 138 )。
    6. 选择 ( \frac{19}{23} ),得到 ( S = 114 )。
    7. 选择 ( \frac{1}{3} ),得到 ( S = 38 )。
    8. 选择 ( \frac{1}{19} ),得到 ( S = 2 ),即 ( 2^1 ),记录指数1。

    输出1

    • 1

    信息

    ID
    784
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者