题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4259
1 3 10 3 52 4 0 0
1 4 13
题意:
给出 n 张卡片, 分给k个人, 从 1 - n 轮流分。
然后,重新把卡片放在一起。第1个人的卡片放在最上边,后面的依次放下面。
再重新分,再放,直到最后变成初始的顺序;
求一共换了多少次!
PS:http://blog.csdn.net/xdu_truth/article/details/7933410
朴素思想:模拟对每个点进行变换,分别求得周期Ci,然后求他们的最小公倍数。(TLE)
优化:可以得知当某个位置上的卡牌由A变回到A是,会经历一个A->B->C->...->A的密闭循环,
这样对于循环内的每个元素,只需要计算其中任一元素即可。
代码如下:#include <cstdio> #include <cstring> #define maxn 847 #define LL __int64 int a[maxn][maxn], b[maxn]; LL GCD(LL a, LL b) { if(b == 0) return a; return GCD(b,a%b); } int main() { int n, k; int vis[maxn]; while(~scanf("%d%d",&n,&k)) { if(n==0 && k==0) break; memset(vis, 0,sizeof(vis)); int cnt = 1; int i; for(i = 0; ; i++) { for(int j = 0; j < k; j++) { a[i][j] = cnt++; } if(cnt > n) break; } cnt = 1; for(int j = 0; j < k; j++) { for(int h = i; h >= 0; h--) { if(a[h][j] && a[h][j] <= n) b[cnt++] = a[h][j]; } } LL ans = 1, cont; for(int i = 1; i <= n; i++) { if(!vis[i]) { cont = 0; int t = i; while(1) { if(vis[t]) break; vis[t] = 1; t = b[t]; cont++; } ans = ans/GCD(ans,cont)*cont;//最小公倍数 } } printf("%I64d\n",ans); } return 0; }
原文地址:http://blog.csdn.net/u012860063/article/details/43704513