题目链接:
http://oj.alpc.cn/Problem/Details?cid=9&tid=A
题意:
问1到N的数任意排列中,最小的x从1出发回到1的x。
思路:
即求前N个数的最小公倍数。
递推会错,因为MOD一个数以后它本身的公倍数将发生改变。
想过大数处理,然而并没有这么大的内存空间。
想过把每个数唯一分解一下,即用唯一分解定理,取前n个的数位于某质数幂的最大值。这时候已经很接近答案了,然而卡住。
正解是单次查询,对N求某个质数L能取到的最大幂次K,然后答案乘上L^K。原理是前N个数中总有一个数能整除L^K,这样就简单的处理出所有质数能取到的最大幂次。
源码:
#include <cstdio>#include <cstring>#include <string>#include <algorithm>#include <iostream>#include <queue>using namespace std;typedef long long LL;const int MAXN = 1e5;const LL MOD = 1e9+7;LL lv[MAXN+5];int vis[MAXN+4];int prime[MAXN+5],cnt;int xi[MAXN+5];void init(){ cnt = 0; memset(vis, 0, sizeof(vis)); for(int i=2; i<=MAXN; i++){ if(vis[i] == 0){ prime[cnt++] = i; int now = i; while(now <= MAXN){ vis[now] = 1; now += i; } } }// lv[1] = 1;// for(int i=0; i<cnt; i++)// xi[i] = 1;// for(int i=2; i<=MAXN; i++){// LL ans = 1;// for(int j=0; j<cnt; j++){// if(prime[j] > i){ printf("prime[j] = %d\n",prime[j]); printf("i = %d\n",i); system("pause");// break;// }// else{// while(xi[j] * prime[j] <= i){// xi[j] *= prime[j];// } printf("second\nj = %d,xi[j] = %d\n",j,xi[j]);// ans = (ans * xi[j]) % MOD;// }// }// lv[i] = ans;// }}void solve(int n){ LL ans = 1; for(int j=0; j<cnt; j++){ if(prime[j] > n) break; LL tt = prime[j]; while(tt * prime[j] <= n){ tt *= prime[j]; } ans = (ans * tt) % MOD; } printf("%I64d\n",ans);}int main(){ init(); int n; while(scanf("%d",&n) != EOF){// printf("%I64d\n",lv[n]); solve(n); } return 0;}