【bzoj1965】【AHOI2005】洗牌

来源:互联网 发布:怎样做seo 编辑:程序博客网 时间:2024/05/20 07:33

题意

  有一副牌,共n张(n为偶数),每一次洗牌将其均分为上下两叠,然后取下叠第一张为新的第一张,上叠第一张为新的第二张,下叠第二张为新的第三张……求经过m次洗牌后,第l张牌的面值(初始为1n

解法

模拟:
  这道题比较容易,只要能够一步一步地分析下去:
  首先可以知道,对于现在处于第x张的牌来说,有:
  ①.若其在上叠(xn2),那么洗牌后它将会去到2x的位置
  ②.若其在下叠(x>n2),那么洗牌后它将会去到2x1的位置
  所以,最暴力的做法:开一个滚动数组,不停地向前模拟,得分20%
  如果将上面的式子变形,可以得到,对于现在处于第x张的牌来说,有:
  ①.若x为奇数,那么在洗牌前,这一张牌的位置是:n+x+12
  ②.若x为偶数,那么在洗牌前,这一张牌的位置是:x2
  所以高级一点的暴力就是采用递归,不停的求解,由于爆栈,所以得分50%
  如果将递归改为递推,那么可以得到70%,最后的三个点会超时
  继续考虑优化:一个数x经过若干次变化之后,必定又会变回x,我们假设经过n+1次洗牌,那么x已经变化n+1次,而至多只有n个数,所以肯定又会变回去
  于是我们首先模拟找到变化的循环节,然后用m对循环节取余,然后剩下的余数部分再次暴力模拟即可

复杂度

O(klogm),k为一不确定数字,大概在11000

20分代码

#include<iostream>#include<cstdlib>#include<cstdio>using namespace std;const int MAXN=10000010;int w[2][MAXN];int n,m,l,cur;int main(){    scanf("%d%d%d",&n,&m,&l);    for(int i=1;i<=n;i++)   w[0][i]=i;    while( m-- )    {        for(int i=1;i<=n/2;i++)   w[cur^1][2*i]=w[cur][i];        for(int i=1;i<=n/2;i++)   w[cur^1][2*i-1]=w[cur][i+n/2];        cur^=1;    }    printf("%d\n",w[cur][l]);    return 0;}

50分代码

#include<iostream>#include<cstdlib>#include<cstdio>using namespace std;const int MAXN=10000010;int n,m,l,ans;void work(int k,int pos){    if( !k )   { ans=pos;return ; }    if( pos%2 )   work( k-1,n/2+(pos+1)/2 );    else   work( k-1,pos/2 );}int main(){    scanf("%d%d%d",&n,&m,&l);    work( m,l );    printf("%d\n",ans);    return 0;}

70分代码

#include<iostream>#include<cstdlib>#include<cstdio>using namespace std;int n,m,l;int main(){    scanf("%d%d%d",&n,&m,&l);    for(int i=1;i<=m;i++)    {        if( l%2 )   l=n/2+(l+1)/2;        else   l=l/2;    }    printf("%d\n",l);    return 0;}

100分代码

#include<iostream>#include<cstdlib>#include<cstdio>#define Lint long long intusing namespace std;Lint n,m,l,x,cnt=1;int main(){    scanf("%d%d%d",&n,&m,&l);    if( l%2 )   x=n/2+(l+1)/2;    else   x=l/2;    while( x!=l )    {        cnt++;        if( x%2 )   x=n/2+(x+1)/2;        else   x=x/2;    }    m=m%cnt;    for(int i=1;i<=m;i++)        if( l%2 )   l=n/2+(l+1)/2;        else   l=l/2;    printf("%d\n",l);    return 0;}
原创粉丝点击