【BZOJ1300】[LLH邀请赛]大数计算器【快速幂】【姿势】

来源:互联网 发布:ubuntu zip分卷压缩 编辑:程序博客网 时间:2024/05/14 12:04

【题目链接】

比较有意思...

经典的组合数取模问题,我们用质因数分解解决。

低位的计算就不说了,直接快速幂取模就可以。

对于高位的计算,我们计算log10下的答案,即log10(p1^a1*p2^a2*...*pk^ak) = a1*log10(p1) + a2*log10(p2) + ... + ak*log10(pk)

记上式为ans,那么答案应该为10^ans,但是我们只要最高位的前三位,怎么处理呢?

我们知道floor(log10(x))+1表示一个数在十进制下的位数,10^floor(log10(x))就是x最高位的十进制基(名词是我口胡出来的...举个例子,123,10^floor(log10(123))=100)

用10^ans除以10^floor(log10(ans)),整数部分就是最高位数,那么用10^ans除以10^(floor(log10(ans))-2),整数部分就是最高位的三位数。

/* Forgive me Not */#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std;typedef long long LL;typedef double DB;typedef long double LD;const int maxn = 1000005;const LL p = 1000000000000LL;int n, m, prime[maxn], cnt, mn[maxn], num[maxn];bool isnotprime[maxn];inline void getprime(int n) {isnotprime[1] = 1;for(int i = 2; i <= n; i++) {if(!isnotprime[i]) prime[++cnt] = i, mn[i] = cnt;for(int j = 1; j <= cnt && i * prime[j] <= n; j++) {isnotprime[i * prime[j]] = 1;mn[i * prime[j]] = j;if(i % prime[j] == 0) break;}}}inline LL qpow(int a, int n) {LL res = 1;for(; n; n >>= 1, a = a * a % p) if(n & 1) res = res * a % p;return res;}inline void add(int n, int f) {for(; n > 1; n /= prime[mn[n]]) num[mn[n]] += f;}int main() {scanf("%d%d", &n, &m);getprime(n);for(int i = 1; i <= n; i++) add(i, 1);for(int i = 1; i <= m; i++) add(i, -1);for(int i = 1; i <= n - m; i++) add(i, -1);LL ans = 1; DB dig = 0.0;for(int i = 1; i <= cnt; i++) if(num[i]) {ans = ans * qpow(prime[i], num[i]) % p;dig += log10(prime[i]) * num[i];}if(dig < 12) printf("%lld\n", ans);else {LD ans2 = pow(10, dig - (int)dig + 2);printf("%lld...%lld\n", (LL)ans2, ans % 1000000000);}return 0;}


0 0
原创粉丝点击