-和尚-

导航

HDU 4259 Double Dealing

题目讲述的就是一个取牌游戏,一轮一轮地轮流取牌,直到最后的牌和一开始的一样(1,2,3,4.。。。。。,n);这样经历了几次,输出它的经过多少次数才回来原位。这道题比赛的时候一开始想到模拟(超了),其实模拟我是看他好长的时间限制才这样想的,没想到真的超了!后来就想找找规律!谁知道找不到!于是就没AC!后来回来宿舍才听舍友说用置换群做!惨死。。。。。。置换群?现在都不是很懂!不过听他说就是把第一次取牌后的结果对其寻找!假如就是输入10 3,这样说吧!下标依次为1,2,3,4,5,6,7,8,9,10;

第一次的结果就是    10 7 4 1 8 5 2 9 6 3,然后

那么置换群为

1->10->3->4->1;da[1]=4;2->7->2;da[2]=2;5->8->9->6->5;da[3]=4;最后我们只需要求da[1],da[2],da[3],的最小公倍数(4)就行了!具体的过程就是这样!这规律还真难找到!这题说到底就是求置换群!

AC代码:

#include"stdio.h"

#include"string.h"

__int64 gcd(__int64 a,__int64 b)

{

      if(b==0)

           return a;

      return gcd(b,a%b);

}

int main()

{

      __int64 str[805],vist[805],i,j,k,l,n,sum,temp;

      while(scanf("%I64d%I64d",&n,&k),n||k)

      {

           if(n<k)

           {

                 printf("1\n");

                 continue;

           }

           temp=l=1;

           for(i=1;i<=k&&i<=n;i++)

           {

                 for(j=(n-i)/k*k+i;j>=1;j-=k)

                 {

                      str[l++]=j;

                      vist[l-1]=0;

                 }

           }

           for(i=1;i<=n;i++)

           {

                 sum=0;

                 if(vist[i]==0)

                 {

                      l=i;

                      while(vist[l]==0)

                      {

                            sum++;

                            vist[l]=1;

                            l=str[l];

                      }

                      temp=sum/gcd(temp,sum)*temp;//这个地方不能变换成(sum*temp)/gcd(tem,sum)!我在这里错了很多次!

                 }

           }

           printf("%I64d\n",temp);

      }

      return 0;

}

posted on 2012-08-28 16:10  -和尚-  阅读(187)  评论(0编辑  收藏  举报