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;
}