/* *State: HDU4259 7796MS 3520K 1468 B C++ *题目大意: * 一副牌有n张,有k个人,轮流发牌,最后把每个人的牌按照小号在上,大号在下 * 的顺序叠放起来,求最少次数使牌恢复原样。 *解题思路: * 发现每一张牌都有出现的周期,要恢复原状,只要求出每张牌出现的周期的最小 * 公倍数即可。 *解题感想; * 用了STL里面的栈,结果20000ms都TLE了。可能是本题数据量太大,不过以后要慎用。 * 贡献了4~5个wa,查了好久好久,原来是这里虽然是_int64,但没有考虑到res[0] * * res[1] / gcd(res[0], res[1]);这样会爆掉,所以一直wa. */
View Code
#include <iostream> #include <cmath> #include <stack> using namespace std; const int MAXN = 1805; int a[2][MAXN], vst[MAXN], cnt;//cnt用来计算周期 int myS[MAXN][MAXN], top[MAXN]; void init() { memset(vst, 0, sizeof(vst)); } void dfs(int x) { cnt++; vst[x] = 1; int nx = a[1][x]; if(!vst[nx]) { dfs(nx); } } __int64 gcd1(__int64 a, __int64 b) { __int64 r = b, t; while(r) { t = r; r = a % r; a = t; } return a; } __int64 gcd2(__int64 a, __int64 b) { return b == 0 ? a : gcd2(b, a % b); } int main(void) { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif int n, k; while(scanf("%d %d", &n, &k), n || k) { init(); for(int i = 0; i < n; i++) { int in = i % k; myS[in][top[in]++] = i; } int s = 0; for(int i = 0; i < n; i++) a[0][i] = i; for(int in = 0; in < k; in++) { while(top[in]) { a[1][s++] = myS[in][--top[in]]; } } int c = 0; __int64 res[MAXN]; for(int i = 0; i < n; i++) { if(!vst[i]) { cnt = 0; dfs(i); res[c++] = cnt; } } __int64 tmp; if(c >= 2) { //这里虽然是_int64,但没有考虑到res[0] * res[1] / gcd(res[0], res[1]);这样会爆掉,所以一直wa. tmp = res[0] / gcd2(res[0], res[1]) * res[1]; for(int i = 2; i < c; i++) tmp = tmp / gcd2(tmp, res[i]) * res[i]; } else if(c == 1) tmp = res[0]; printf("%I64d\n", tmp); } return 0; }