【BZOJ1300】[LLH邀請賽]大數計算器【快速冪】【姿勢】

【題目鏈接】

比較有意思...

經典的組合數取模問題,我們用質因數分解解決。

低位的計算就不說了,直接快速冪取模就可以。

對於高位的計算,我們計算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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章