문제 D. 한강
Large 푸는데 1분 30초정도 걸린다. 그리고 메모리는 3.5기가 정도 차지한다. 메모리를 많이 먹는 건 조금 바보같이 코딩해서 그렇다. 소수를 구하는 코드를 꼬꼬마 시절 작성한 코드에서 긁어와서 좀 지저분하기도 하다.
키워드: 소수, 소인수분해, 에라토스테네스
http://algospot.com/forum/read/1322/
http://algospot.com/forum/read/1324/
Large 푸는데 1분 30초정도 걸린다. 그리고 메모리는 3.5기가 정도 차지한다. 메모리를 많이 먹는 건 조금 바보같이 코딩해서 그렇다. 소수를 구하는 코드를 꼬꼬마 시절 작성한 코드에서 긁어와서 좀 지저분하기도 하다.
키워드: 소수, 소인수분해, 에라토스테네스
http://algospot.com/forum/read/1322/
http://algospot.com/forum/read/1324/
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <cassert>
#include <ctime>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
#ifndef CHAR_BIT
define CHAR_BIT 8
#endif
#define UINT_BITS 32
#define LARGEINT unsigned int
#define LARGEINT_MAX UINT_MAX
#define LINE 10
#define N_MAX 100000000000000000ll
#define PRIME_MAX 1000000007
typedef long long int lli;
vector<int> prime_list;
vector<lli> pow_table[51000000];
int pow_max[51000000];
#if 0
// for small data set
#define N_MAX 1000000ll
#define PRIME_MAX 1000000
#endif
unsigned int *makebitarray(LARGEINT arraysize)
{
unsigned int *bitarray;
// if (!arraysize) arraysize=1;
LARGEINT q=arraysize/UINT_BITS;
if (arraysize%UINT_BITS) q++;
/* -----_check overflow */
if ( (!q) || (q>LARGEINT_MAX/sizeof(unsigned int)) ) {
bitarray=NULL;
} else {
bitarray=(unsigned int*) calloc(sizeof(unsigned int),q);
}
return bitarray;
}
int freebitarray(unsigned int *bitarray)
{
free(bitarray);
return 0;
}
inline unsigned int getbit(const unsigned int * const bitarray, const LARGEINT nth)
{
LARGEINT q=nth/UINT_BITS;
unsigned int r=nth%UINT_BITS;
return ((*(bitarray+q))>>r)&1;
}
inline void setbit1(unsigned int * const bitarray, const LARGEINT nth)
{
LARGEINT q=nth/UINT_BITS;
unsigned int r=nth%UINT_BITS;
(*(bitarray+q)|=(1<<r));
}
inline void setbit0(unsigned int * const bitarray, const LARGEINT nth)
{
LARGEINT q=nth/UINT_BITS;
unsigned int r=nth%UINT_BITS;
(*(bitarray+q)&=~(1<<r));
}
int initbitarray(unsigned int *bitarray, const LARGEINT arraysize, const int TorF)
{
LARGEINT q=arraysize/UINT_BITS;
if (arraysize%UINT_BITS) q++;
if (TorF) {
while (q--) *(bitarray++)=~0;
} else {
while (q--) *(bitarray++)=0;
}
return 0;
}
void calc_prime_list()
{
unsigned int n_of_prime=0, end, i, j, n, nsq;
unsigned int *numbers;
time_t a,b;
end = PRIME_MAX; // 10^9
if (end<3) {
for (i=2;i<=end;i++) {
for (j=2; (j*j<=i) && (i%j) ; j++);
if (j*j>i) printf("%d%c",i,(++n_of_prime%10)?' ':'\n');
}
printf("\n\t%d prime(s)\n",n_of_prime);
exit(0);
}
//a=clock();
/* 홀수만 저장하므로 절반만 할당 */
numbers=makebitarray(end/2);
if (NULL==numbers) {
printf("error: 메모리 할당이 불가능합니다.\n"
"프로그램을 종료합니다.\n");
fflush(stdout);
exit(1);
}
initbitarray(numbers,end/2,1);
setbit0(numbers,0); /* 1은 소수가 아님 */
//printf("2 ");
n_of_prime++;
for (i=1, n=3, nsq=9; (nsq<=end) && (nsq>2*n) ; i++, nsq+=(4*n+4), n+=2) {
if ( getbit(numbers,i) ) {
for (j=nsq/2; (j<=end/2) ; j+=n) {
setbit0(numbers,j);
}
}
}
fprintf(stderr, "calc_prime_list: sieving done\n");
prime_list.push_back(2);
i=0, n=1;
while( i++, n+=2, (n<=end) && (n>i) ) {
if ( getbit(numbers,i) ) {
prime_list.push_back(n);
}
}
freebitarray(numbers);
//b=clock();
//printf("\n\t%u prime(s)",n_of_prime);
//printf("\n\ttime: %fs\n",(double) (b-a)/CLOCKS_PER_SEC);
//fflush(stdout);
fprintf(stderr, "calc_prime_list: done\n");
}
void calc_pow_table()
{
int imax = prime_list.size();
//double logN = log((double) N_MAX);
for (int i = 0; i < imax; ++i) {
const int base = prime_list[i];
//fprintf(stderr, "calc_pow_table: %d, %d\n", i, base);
//double log_base = log((double) base);
//int jmax = (int) (logN / log_base);
pow_table[i].push_back(1);
lli tmp = 1;
int j = 0;
for (j = 1; tmp <= N_MAX/base; ++j) {
tmp *= base;
pow_table[i].push_back(tmp);
}
pow_max[i] = j - 1;
}
fprintf(stderr, "calc_pow_table: done\n");
}
lli get_num_div(lli N, lli *d0)
{
*d0 = 0;
lli sqrtN = (lli) sqrt((double) N);
if ((sqrtN + 1)*(sqrtN + 1) <= N) {
fprintf(stderr, "!\n");
++sqrtN;
}
int D = 1;
int imax = prime_list.size();
for (int i = 0; i < imax; ++i) {
int p = prime_list[i];
if (p > sqrtN)
break;
int cnt = 1;
while (!(N % p)) {
N /= p;
++cnt;
if (*d0 == 0)
*d0 = p;
}
D *= cnt;
if (N == 1)
break;
}
if (N != 1)
D *= 2;
return D;
}
bool comp(pair<int,lli> a, pair<int,lli> b)
{
return (a.second < b.second);
}
lli foo2(const lli N, const int mi) // D == 2
{
int low = mi;
int high = prime_list.size() - 1;
if (N > prime_list[high]) {
fprintf(stderr, "error binary search\n");
return high - low;
}
const int N2 = (int) N; // for faster comparison
while (low < high) {
int mid = low + (high - low) / 2;
if (prime_list[mid] > N2) {
high = mid;
} else {
low = mid + 1;
}
if (mid == low)
break;
}
if (prime_list[low] > N2) {
return (low - mi);
} else if (prime_list[high] > N2) {
fprintf(stderr, "warning binary search\n");
return (high - mi);
} else {
fprintf(stderr, "error binary search\n");
fprintf(stderr, "\t%lld %d\n", N, mi);
return (high - mi);
}
}
// D == (p + 1) && x == a ** p
lli foo_pow(const lli N, const int mi, const int p)
{
if (mi >= prime_list.size())
return 0ll;
if (p > pow_max[mi] || pow_table[mi][p] > N)
return 0ll;
int low = mi;
int high = prime_list.size() - 1;
while (low < high) {
int mid = low + (high - low) / 2;
if (p > pow_max[mid] || pow_table[mid][p] > N) {
high = mid;
} else {
low = mid + 1;
}
if (mid == low)
break;
}
if (p > pow_max[low] || pow_table[low][p] > N) {
return (low - mi);
} else if (p > pow_max[high] || pow_table[high][p] > N) {
fprintf(stderr, "warning binary search pow\n");
return (high - mi);
} else {
fprintf(stderr, "error binary search pow\n");
fprintf(stderr, "\t%lld %d\n", N, mi);
return (high - mi);
}
}
lli foo4(const lli N, const int mi) // D == 4
{
if (mi >= prime_list.size()) {
return 0ll;
}
if (prime_list[mi] > N) {
return 0ll;
}
if (2 > pow_max[mi] || pow_table[mi][2] > N)
return 0ll;
lli r = 0;
// case 1: x = a * a * a
r += foo_pow(N, mi, 3);
// case 2: x = a * b
const int imax = prime_list.size();
for (int i = mi; i < imax; ++i) {
lli N2 = N / prime_list[i];
if (i + 1 >= imax || N2 < prime_list[i + 1])
break;
r += foo2(N2, i + 1);
}
return r;
}
lli foo(const lli N, const int mi, const int D)
{
//printf("!foo %lld %d %d\n", N, mi, D);
if (N <= 0) {
fprintf(stderr, "ERROR\n");
return 0ll;
}
switch (D) {
case 1:
return 1ll;
break;
case 2:
return foo2(N, mi);
break;
case 3:
//return foo_pow(N, mi, 2);
break;
case 4:
return foo4(N, mi);
break;
case 5:
//return foo_pow(N, mi, 4);
break;
}
if (mi >= prime_list.size()) {
return 0ll;
}
if (prime_list[mi] > N) {
return 0ll;
}
if (D >= 5) {
if (3 > pow_max[mi] || pow_table[mi][3] > N)
return 0ll;
} else if (D >= 3) {
if (2 > pow_max[mi] || pow_table[mi][2] > N)
return 0ll;
}
lli r = 0;
int imax = D;
if (imax > (pow_max[mi] + 1))
imax = pow_max[mi] + 1;
for (int i = 1; (i + 1) <= imax; ++i) {
if (D % (i + 1))
continue;
if (i >= 1 && pow_table[mi][i] <= 1)
fprintf(stderr, "ERROR2\n");
lli N2 = N / pow_table[mi][i];
if (!N2)
break;
int D2 = D / (i + 1);
if (D2 > 1 && N2 < prime_list[mi + 1])
break;
if (D2 == 1)
r += 1;
else
r += foo(N2, mi + 1, D2);
}
return r + foo(N, mi + 1, D); // skip prime_list[mi]
}
int find_mi(const lli M)
{
int low = 0;
int high = prime_list.size() - 1;
while (low < high) {
int mid = low + (high - low) / 2;
if (prime_list[mid] >= M) {
high = mid;
} else {
low = mid + 1;
}
if (mid == low)
break;
}
if (prime_list[low] >= M) {
return low;
} else if (prime_list[high] >= M) {
return high;
} else {
assert(high == prime_list.size() - 1);
return -1;
}
}
int main(void)
{
calc_prime_list();
calc_pow_table();
int T_;
scanf("%d", &T_);
vector< pair<int,lli> > gg;
for (int i_ = 1; i_ <= T_; ++i_) {
gg.clear();
long long int ans = 0;
lli N, M;
scanf("%lld %lld", &N, &M);
//fprintf(stderr, "! step 0\n");
int mi = -1;
lli d0;
const lli num_div_N = get_num_div(N, &d0);
if (num_div_N == 2) {
//fprintf(stderr, "! num_div\n");
goto final;
}
//fprintf(stderr, "! step 1\n");
//printf("num_div_%lld: %lld\n", N, num_div_N);
mi = find_mi(M);
if (mi == -1) {
//fprintf(stderr, "! mi\n");
goto final;
}
//fprintf(stderr, "! step 2\n");
ans = foo(N, mi, num_div_N);
// subtract 1 to exclude N
if (d0 >= M)
--ans;
final:
fprintf(stderr, "Case #%d: %lld\n", i_, ans);
printf("Case #%d: %lld\n", i_, ans);
}
return 0;
}
