先用线性素数筛筛选出某一范围的素数,然后可以把若干数分解成素数相乘的多项式(大白话:小学五年级的质因子分解)。
可以解决组合数问题,避免中间数据太大无法表示的问题。
以 UVA Choose and divide 为例\
#include <iostream>
#include <cstring>
#include <iomanip>
#include <cmath>
using namespace std;
const int N = 10000;
bool vis[N + 1];
int p[1229], cnt_p;
int getPrime(int n) {
memset(vis, 1, sizeof vis);
int cnt = 0;
for (int i = 2; i <= n; ++i) {
if(vis[i]) {
p[cnt++] = i;
}
for (int j = 0; j < cnt && (i *p[j] <= n); ++j) {
vis[i * p[j]] = 0;
if(i % p[j] == 0) break;
}
}
return cnt;
}
int e[1229];
inline void add_integer(int n, int d) {
//d = 1,表示乘;-1表示除
for(int i = 0; i < cnt_p; ++i) {
while(n % p[i] == 0) {
n /= p[i];
e[i] += d;
}
if(n == 1) break;
}
}
inline void add_factorial(int n, int d) {
for (int i = 1; i <= n; ++i)
add_integer(i, d);
}
int main()
{
int P, q, r, s;
cnt_p = getPrime(10000); //1229
while(cin >> P >> q >> r >> s) {
memset(e, 0, sizeof e);
add_factorial(P, 1);
add_factorial(q, -1);
add_factorial(P - q, -1);
add_factorial(r, -1);
add_factorial(s, 1);
add_factorial(r - s, 1);
double ans = 1.0;
for (int i = 0; i < cnt_p; ++i) {
ans *= pow(p[i], e[i]);
}
cout << fixed << setprecision(5) << ans << endl;
}
return 0;
}
\
\
UVA Minimum Sum LCM Minimum Sum LCM
#include <iostream>
#include <cmath>
using namespace std;
long long work(long long n, long long f[]) { //分解
long long cnt = 0;
long long m = sqrt(n + 0.5);
for (long long i = 2; i <= m && i <= n; ++i) {
if(n % i == 0) {
f[cnt] = i; n /= i;
while(n % i == 0) {
f[cnt] *= i;
n /= i;
}
cnt++;
}
}
if(n > 1) f[cnt++] = n;
return cnt;
}
int main()
{
//我对拍的都没错,一怒之下,把很多数据范围改了long long,就过了
//可能是1e5 ~ 1e9中间哪的数据溢出了
long long kase = 0, n;
while(cin >> n && n) {
long long f[33] = {0};
long long cnt = work(n, f);
long long sum = 0;
if(cnt <= 1) sum = n + 1;
else {
for(long long i = 0; i < cnt; ++i)
sum += f[i];
}
cout << "Case " << ++kase << ": " << sum << endl;
}
return 0;
}
\