您的位置:首页 > 其它

2012 ACM/ICPC Asia Regional Online Warmup-1003

2012-08-28 18:59 465 查看
/*

http://acm.hdu.edu.cn/showproblem.php?pid=4259

题意是:给定一个排列和一个特定的置换,最后问你最少要多少步置换才能回到原来的状态

解题思路就是:找出置换中的各个置换回路的长度,答案就是各个置换回路的最小公倍数

举个例子:

排列:1 2 3 4 5 6

置换:2 3 5 4 1 6

那么第一个置换回路是1 2 3 5,长度为4,第二个置换回路是 6,长度为1;

所以答案就是4和1的最小公倍数4

而这题的关键就是我们要找到这个置换,也就是初始排列第一次被转换后的结果

假设n为10,k为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,长度为4

第二个回路为:2,7,长度为2

第三个回路为:5,8,9,6,长度为4

所以答案就是4,4,2的最小公倍数4

代码如下:

*/

#include<stdio.h>
#include<string.h>
int vis[810],std[810],num[810][810];

__int64 gcd(__int64 a,__int64 b)
{
return b==0?a:gcd(b,a%b);
}
__int64 solve(int n,int k)
{
int p,i,j,cnt;
__int64 sum=1,tem,d;
for(i=1;i<=k;i++)
{
j=i;
cnt=0;
while(j<=n)
{
num[i][++cnt]=j;
j+=k;
}
num[i][0]=cnt;
}
cnt=0;
for(i=1;i<=k;i++)
{
for(j=num[i][0];j>=1;j--)
std[++cnt]=num[i][j];
}
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++)
{
if(!vis[i])
{
tem=1;
vis[i]=1;
p=i;
while(std[p]!=i)
++tem,p=std[p],vis[p]=1;
d=gcd(sum,tem);
sum/=d;
sum*=tem;
}
}
return sum;
}
int main()
{
int n,k;
while(scanf("%d%d",&n,&k),n+k)
printf("%I64d\n",solve(n,k));
return 0;
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: