辽宁省赛2010 G

来源:互联网 发布:腾讯视频制作软件 编辑:程序博客网 时间:2024/05/01 15:15

题目链接:https://ac.2333.moe/Problem/view.xhtml?id=1225

比赛链接:https://vjudge.net/contest/157779#overview

题目大意:给定n、m、x,原始序列是1~n;问m次操作之后的序列的前1~x个数是什么;每次操作,先取出偶数位置的数,按位置顺序构成一个序列a,再取出奇数位置的数,按位置顺序构成一个序列b,最后新的序列就是a+b。

分析:和上次的洗牌问题差不多,洗牌问题是判断第一个数1的位置的变化,问多少次操作之后能回到原来的顺序。
而这道题的操作差不多,我们需要判断m次操作后第1~X的位置分别是几。观察的时候我们可以只看第一个位置,找出其变化规律(和洗牌问题的规律类似):
      当pos(当前位置的数字)<=n/2时,下一次的变化就是pos*=2;
      否则:pos=(pos-n/2)*2-1;
就这样判断m次操作后每个位置的数是多少。
但m很大,这样肯定会超时,我们可以预处理一下m,根据洗牌问题的启发,我们先判断多少次之后会变回原来的顺序,然后让m取余这个数,再操作m次就行了。

洗牌问题:http://blog.csdn.net/jane_jxr/article/details/65627522

CODE:

#include<stdio.h>#include<stdlib.h>#include<iostream>#include<algorithm>#include<math.h>#include<map>#include<queue>#include<stack>#include<string.h>typedef long long LL;using namespace std;#define INF 0x3f3f3f3fconst double eps=0.0001;const int maxn=10005;int n,m,x;int judge(int xx,int kk)//kk次操作之后xx位置的数是什么{    int pos=xx;    while(kk--)    {        if(pos<=n/2)            pos=pos*2;        else            pos=(pos-n/2)*2-1;    }    return pos;}int main(){    while(~scanf("%d%d%d",&n,&m,&x))    {       // cout<<judge(1,5)<<" ";        int pos1=2,anss=1;        while(pos1!=1)//判断多少次之后回到原来的位置        {            if(pos1<=n/2)                pos1*=2;            else                pos1=(pos1-n/2)*2-1;            anss++;        }        for(int i=1;i<=x;i++)//枚举求前x个数        {            int ans=judge(i,m%anss);            if(i>1)                printf(" ");            printf("%d",ans);        }        printf("\n");    }    return 0;}

0 0
原创粉丝点击