P13518 [KOI 2025 #2] 镜子

解题思路

核心观察:每次使用镜子相当于进行一次对称变换,位置从 a 变为 2b - a。经过数学推导可以发现,最终的终点位置可以表示为:

终点 = 2×(某些镜子的位置) - 2×(另一些镜子的位置) + ... + (-1)^N × 初始位置

关键规律:

  • 当镜子数量为偶数时,最终位置与初始位置的符号相同

  • 当镜子数量为奇数时,最终位置与初始位置的符号相反

  • 要最大化最终位置,需要让正系数的镜子位置尽可能大,负系数的镜子位置尽可能小

算法策略:

  1. n=1或2:直接模拟所有可能的顺序

  2. n为偶数且初始位置在两个中间镜子之间:采用交替左右跳跃的策略

  3. 其他情况:根据n的奇偶性决定起始跳跃方向,然后交替左右跳跃

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N = 2e5 + 10,inf = 0x3f3f3f3f;
    ll n,k,a[N];  // n:镜子数量, k:初始位置, a:镜子位置数组
    ll ans;
    
    // 处理n=1或2的情况:直接模拟所有可能的顺序
    void solve1(){
        if(n == 1) k = 2 * a[1] - k;  // 只有一个镜子,直接对称
        if(n == 2) {
            // 两个镜子,按顺序1->2使用
            k = 2 * a[1] - k;
            k = 2 * a[2] - k;
        }
    }
    
    // 处理子任务2和3的情况:n为偶数且初始位置在两个中间镜子之间
    void solve2(){
        int L = 1,R = n,id = 1;  // L,R:左右指针, id:标识当前跳跃方向
        while(L <= R){
            if(id % 2 == 1) k = 2 * a[L] - k,L++;  // 奇数步:用左边镜子,向右跳
            if(id % 2 == 0) k = 2 * a[R] - k,R--;  // 偶数步:用右边镜子,向左跳
            id++;
        }
    }
    
    // 处理子任务4的情况:一般情况
    void solve4(){
        int L = 1,R = n,id;
        // 根据n的奇偶性决定起始跳跃方向
        if(n % 2 == 1) id = 0; // n为奇数:实现最开始往右跳
        if(n % 2 == 0) id = 1; // n为偶数:默认从左开始跳
        
        while(L <= R){
            if(id % 2 == 1) k = 2 * a[L] - k,L++;  // 用左边镜子
            if(id % 2 == 0) k = 2 * a[R] - k,R--;  // 用右边镜子
            id++;
        } 
    }
    
    int main()
    {
        cin >> n >> k;
        for(int i = 1; i <= n; i++) cin >> a[i];
        
        // 根据不同的情况选择相应的解法
        if(n == 1 || n == 2) solve1();  // 情况1:镜子数量少,直接模拟
        else if(n % 2 == 0 && a[n / 2] < k && k < a[n / 2 + 1]){ // 子任务2,3:偶数且初始位置在中间
            solve2();        
        }
        else{ // 子任务4:其他所有情况
            solve4();
        } 
        
        cout << k << endl;  // 输出最终位置
        return 0;
    }

     

posted @ 2025-10-26 09:37  CRt0729  阅读(6)  评论(0)    收藏  举报