1.题目描述:点击打开链接
2.解题思路:本题要求LCM(C(n,0), C(n,1),..., C(n,n)),官方题解是转化为求解LCM(1,2,3,...n+1)/(n+1),然而这种做法还是觉得太陌生,不妨试着用学过的唯一分解定理去做。
首先,求这n+1个数的LCM,实际上就是求所有小于n的素数中,对于每一个素数Pi,哪一项的指数最大,然后把他们连乘起来即可得到LCM值。因此,问题转化为确定每一个pi的最大指数。这里要用到Kummer定理来解决,Kummer定理告诉我们这样一个事实:p恰好整除C(n,k)的指数等于n和k都写成p进制数时候,ni<ki的个数。这里的ni指的是n写成p进制数时候的第i项。实际上等价于n-k和k这两个数按照p进制数相加时,发生的“进位”的次数。由于我们要找最大的指数,即我们希望进位的次数可以尽可能的多。在草稿纸上举几个例子演算后即可发现,如果在第i位第一次发生了进位现象,那么进位后剩下的数一定小于p-1,因为在p进制中,两个加数最大只能是p-1,然而如果想要发生进位后剩下的数也等于p-1,即相加后的结果应该是p+(p-1),这显然是不可能的。这样,只要找到了这个数,那么可以构造一个k,使得后面所有位都发生进位。由此,我们就找到了最大指数。
找到指数之后,利用快速幂计算乘积即可得到答案。
3.代码:
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<algorithm> #include<cassert> #include<string> #include<sstream> #include<set> #include<vector> #include<stack> #include<map> #include<queue> #include<deque> #include<cstdlib> #include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<cctype> #include<functional> using namespace std; #define me(s) memset(s,0,sizeof(s)) #define pb push_back typedef long long ll; typedef unsigned int uint; typedef unsigned long long ull; typedef pair <ll, int> P; const int MOD = 1e9 + 7; const int N = 1000000 + 10; int vis[N]; int primes[N]; int idx; void seive() { int m = sqrt(N); for (int i = 2; i <= m; i++) if (!vis[i]) for (int j = i*i; j<N; j += i) vis[j] = 1; for (int i = 2; i<N; i++) if (!vis[i]) primes[idx++] = i; } ll pow_mod(ll a, int k) { ll res = 1; while (k>0) { if (k & 1)res = res*a%MOD; a = a*a%MOD; k >>= 1; } return res; } int get_pow(int n, int p) { int cnt = 0; int tmp[30]; while (n>0) { tmp[cnt++] = n%p; n /= p; } int res = 0, flag = 0; for (int i = 0; i<cnt - 1; i++) if (tmp[i]<p - 1 + flag)//找到第一个小于p-1的数 { res++; flag = 1; } return res; } int main() { seive(); int T; for (scanf("%d", &T); T--;) { int n; scanf("%d", &n); ll ans = 1; for (int i = 0; i<idx&&primes[i] <= n; i++) { ans = ans*pow_mod(primes[i], get_pow(n, primes[i])) % MOD; } printf("%I64d\n", ans); } }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-14 23:19:03