codeforces 949B.A Leapfrog in the Array

题目大意

给出一个长度为 2 n 1 的序列,其中第 2 i 1 个位置上的数是 i
每次把最后一个数往前跳到第一个遇到的空格上,直到最后n个数都在前n个格子为止。
给出p组询问,求最终序列的某个位置上的数是多少。
比如1 2 3 4 会变成 1324
(CF上的题翻译很egg ache啊)

题解

这是我最后半分钟写出的奇妙解法

通过找规律发现
比如当n=6时,最终数组为1 4 2 6 3 5
显然奇数位是 2 i 1

而把偶数位提出来后
4 6 5 ???
减3后
1 3 2
欸这不就是n=3的情况吗


这是n为偶数的情况,再比如n=7
最终数组为1 6 2 5 3 7 4
提出偶数位
6 5 7
减4
2 1 3
可以显然地发现,实际就是把n=3的情况的最后一位移到第一位
那么实际求就往前移一位

证明

当n为偶数时:
a1 a2 a3 a4…an (n%2==0)
既然是按顺序往前跳,那么前n/2个肯定是不变的
假设先把后n/2个跳到一起,结果就是n/2的方案+n/2
这时前面刚好有n/2个空格,所以可以依次跳到前面的空格里,而顺序不变。


当n为奇数时:
a1 a2 a3 a4…an (n%2==1)
按顺序往前跳,前(n+1)/2个不变
后(n-1)/2就是(n-1)/2的答案+(n+1)/2
然而此时前面有(n+1)/2个空格,但只有(n-1)/2个数,所以跳完一轮后最后一个数会跳到最前

于是就这样乱搞就行了
(似乎没有人跟我方法一样那么就算作原创吧

code

(CF上不能用%lld)

#include <iostream>
#include <cstdlib>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
using namespace std;

long long n,Q,s,i;

long long get(long long t,long long s)
{
    if (s&1) return (s+1)>>1;

    if (t&1)
    {
        if ((s>>1)==1)
        return get(t>>1,t>>1)+(t>>1)+1;
        else
        return get(t>>1,(s>>1)-1)+(t>>1)+1;
    }
    else
    return get(t>>1,s>>1)+(t>>1);
}

int main()
{
    scanf("%I64d%I64d",&n,&Q);

    for (;Q;Q--)
    {
        scanf("%I64d",&s);
        printf("%I64d\n",get(n,s));
    }
}

猜你喜欢

转载自blog.csdn.net/gmh77/article/details/80935248