├── 1. 기본기 잡기 ├── README.md ├── more_sieve_techniques.cpp ├── n_floor_i.cpp ├── sieve_arbitrary_start.cpp ├── sieve_techniques.cpp └── sqrt_n_algorithms.cpp ├── 10. 소수의 개수 빠르게 세기 ├── Lucy_Hedgehog.cpp ├── Meissel_Lehmer.cpp └── README.md ├── 11. more on multiplicative functions ├── README.md ├── min_25_sieve.cpp └── xudyh_sieve.cpp ├── 2. 유클리드, 확장 유클리드 ├── README.md ├── ax=b (mod c).cpp ├── euclidean.cpp └── extended_euclidean.cpp ├── 3. 중국인의 나머지 정리 ├── CRT.cpp └── README.md ├── 4. 페르마 소정리, 오일러 정리 및 활용 ├── BOJ_13970_Power_Tower.cpp ├── README.md └── simple_euler_phi.cpp ├── 5. 팩토리얼과 이항계수 ├── BOJ_14854_mod_n.cpp ├── README.md ├── mod_n.cpp ├── mod_p.cpp └── mod_p^e.cpp ├── 6. Miller-Rabin 소수 판별 알고리즘과 Pollard-Rho 소인수분해 ├── BOJ_4149.cpp └── README.md ├── 7. Mobius function과 그 활용 ├── BOJ_16409_with_mobius.cpp ├── BOJ_16409_without_mobius.cpp ├── README.md ├── divisor_cnt_sum.cpp └── sieve_mobius.cpp ├── 8. 원시근, 이산로그, 이산제곱근 ├── README.md ├── baby_step_giant_step.cpp ├── modular_sqrt_power_odd_prime.cpp ├── modular_sqrt_power_of_2.cpp └── search_generator.cpp ├── 9. 유클리드 알고리즘의 활용 ├── Lattice_Point_Counting.cpp ├── Linear_Inequality_with_Modulo.cpp ├── Minimal_Fraction.cpp ├── Modulo_Maximization_Minimization.cpp └── README.md └── README.md /1. 기본기 잡기/README.md: -------------------------------------------------------------------------------- 1 | # 기본기 잡기 2 | 3 | 블로그 링크 : https://rkm0959.tistory.com/178 4 | 5 | n_floor_i : floor(n/i) 형 값들을 위한 효율적 iteration 6 | 7 | sieve_techniques : 에라토스테네스의 체와 기본 활용법 8 | 9 | more_sieve_techniques : 에라토스테네스의 체의 조금 더 어려운 활용법. 약수의 개수와 약수의 합을 전처리함. Linear Sieve 참고. 10 | 11 | sieve_arbitrary_start : 에라토스테네스의 체를 활용하여, 주어진 구간 내의 소수를 찾는 코드. 12 | 13 | sqrt_n_algorithms : 루트 시간 소인수분해, 소수 판별, 약수 개수 카운팅 14 | -------------------------------------------------------------------------------- /1. 기본기 잡기/more_sieve_techniques.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | bool ispr[1111111]; 10 | int fpr[1111111]; // smallest prime divisor 11 | int cnt_pr[1111111]; // number of distinct prime divisor 12 | int expo[1111111]; // expo[p^k] = k 13 | int sum_pr[1111111]; // sum_pr[p^k] = 1 + p + ... + p^k 14 | int tau[1111111]; // number of divisors 15 | int sig[1111111]; // sum of divisors 16 | int C = 1000000; // sieve size 17 | 18 | 19 | // for reference, O(n log n) from Harmonic Sequence 20 | void easy_tau_sig(void) 21 | { 22 | for(int i=1 ; i<=C ; i++) 23 | for(int j=i ; j<=C ; j+=i) 24 | tau[j]++, sig[j]+=i; 25 | } 26 | 27 | // with sieve, O(n log log n) 28 | int main(void) 29 | { 30 | int i, j; ispr[1]=false; fpr[1]=tau[1]=sig[1]=sum_pr[1]=1; cnt_pr[1]=expo[1]=0; 31 | for(i=2 ; i<=C ; i++) ispr[i]=true, sig[i]=1, tau[i]=1; 32 | for(i=2 ; i<=C ; i++) 33 | { 34 | if(ispr[i] || cnt_pr[i]==1) // i is a prime power 35 | { 36 | if(ispr[i]) fpr[i]=i, cnt_pr[i]=1; 37 | expo[i]=expo[i/fpr[i]]+1; // expo[p^k] = expo[p^(k-1)] + 1 38 | sum_pr[i]=sum_pr[i/fpr[i]]+i; // sum_pr[p^k] = sum_pr[p^(k-1)] + p^k 39 | tau[i]=expo[i]+1; sig[i]=sum_pr[i]; // tau[p^k] = k+1, sig[p^k] = 1 + p + ... + p^k 40 | for(j=2*i ; j<=C ; j+=i) 41 | { 42 | ispr[j]=false; 43 | if(ispr[i]) cnt_pr[j]++; 44 | if(!fpr[j] && ispr[i]) fpr[j]=i; 45 | tau[j]=tau[j]/expo[i]*(expo[i]+1); // p^(k-1) * something -> p^k * something 46 | sig[j]=sig[j]/sum_pr[i/fpr[i]]*(sum_pr[i]); // p^(k-1) * something -> p^k * something 47 | } 48 | } 49 | } 50 | return 0; 51 | } -------------------------------------------------------------------------------- /1. 기본기 잡기/n_floor_i.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | ll mod=1e9+7; 9 | 10 | int main(void) 11 | { 12 | int n=45; int i, la, ans=0; 13 | for(i=1 ; i<=n ; i=la+1) // works in O(sqrt(n)) 14 | { 15 | la=n/(n/i); 16 | cout << "From " << i << " to " << la << " floor(n/i) = " << n/i << "\n"; 17 | } 18 | 19 | // Exercise : find sum_{i=1}^n floor(n/i) in O(sqrt(n)) time 20 | for(i=1, ans=0 ; i<=n ; i=la+1) 21 | { 22 | la=n/(n/i); 23 | ans+=(la-i+1)*(n/i); 24 | } 25 | cout << ans << "\n"; 26 | for(i=1, ans=0 ; i<=n ; i++) ans+=n/i; 27 | cout << ans << "\n"; 28 | return 0; 29 | } -------------------------------------------------------------------------------- /1. 기본기 잡기/sieve_arbitrary_start.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | ll start, n; 10 | bool ispr[1111111]; 11 | // ispr[i] : if (start + i) is prime or not 12 | 13 | bool isprime(ll N) // for test only 14 | { 15 | if(N==1) return false; 16 | for(ll i=2 ; i*i<=N ; i++) 17 | if(N%i==0) return false; 18 | return true; 19 | } 20 | 21 | int main(void) 22 | { 23 | ll i, j; start = 1e9; n = 20000; 24 | for(i=1 ; i<=n ; i++) ispr[i]=true; 25 | for(i=2 ; i*i<=start+n ; i++) 26 | { 27 | ll cur=i*((start+i)/i); 28 | // cur : minimum multiple of i in [start+1, start+n] 29 | for(j=cur ; j<=start+n ; j+=i) 30 | if(j!=i) ispr[j-start]=false; 31 | } 32 | for(i=1 ; i<=n ; i++) assert(isprime(start + i) == ispr[i]); 33 | return 0; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /1. 기본기 잡기/sieve_techniques.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | bool ispr[1111111]; 10 | int fpr[1111111]; // smallest prime divisor 11 | int cnt_pr[1111111]; // number of distinct prime divisor 12 | int phi[1111111]; // euler phi function 13 | int C = 1000000; // sieve size 14 | // ... and much more is possible. ex) mobius function 15 | 16 | void quick_factorize(int n) // logarithmic time, after sieve 17 | { 18 | while(n!=1) 19 | { 20 | int p=fpr[n]; n/=p; 21 | // while(n % p == 0) n /= p; is possible of course 22 | cout << "Found Prime Divisor " << p << "\n"; 23 | // save these values in a data structure, if needed 24 | } 25 | } 26 | 27 | int main(void) 28 | { 29 | int i, j; ispr[1]=false; fpr[1]=1; phi[1]=1; 30 | for(i=2 ; i<=C ; i++) ispr[i]=true, phi[i]=i; 31 | for(i=2 ; i<=C ; i++) 32 | { 33 | if(!ispr[i]) continue; // now i is a prime 34 | fpr[i]=i; cnt_pr[i]=1; phi[i]=i-1; 35 | for(j=2*i ; j<=C ; j+=i) // iterate over all multiples 36 | { 37 | ispr[j]=false; 38 | if(!fpr[j]) fpr[j]=i; 39 | cnt_pr[j]++; phi[j]-=phi[j]/i; 40 | } 41 | } 42 | quick_factorize(8148); 43 | } 44 | 45 | -------------------------------------------------------------------------------- /1. 기본기 잡기/sqrt_n_algorithms.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | bool isprime(ll n) 10 | { 11 | if(n==1) return false; 12 | for(ll i=2 ; i*i<=n ; i++) 13 | if(n%i==0) return false; 14 | return true; 15 | } 16 | 17 | ll cnt_factor(ll n) 18 | { 19 | ll ret=0; 20 | for(ll i=1 ; i*i<=n ; i++) 21 | { 22 | if(n%i==0) 23 | { 24 | if(i*i==n) ret+=1; 25 | else ret+=2; 26 | // if you want all factors, add i, n/i (only one of them if i*i==n) 27 | } 28 | } 29 | return ret; 30 | } 31 | 32 | vector< pair > factorize(ll n) 33 | { 34 | vector< pair > ret; ret.clear(); 35 | for(ll i=2 ; i*i<=n ; i++) 36 | { 37 | if(n%i==0) 38 | { 39 | ll cnt=0; 40 | while(n%i==0) { cnt++; n/=i; } 41 | ret.push_back(make_pair(i, cnt)); 42 | } 43 | } 44 | if(n!=1) ret.push_back(make_pair(n, 1)); 45 | return ret; 46 | } 47 | 48 | int main(void) 49 | { 50 | cout << isprime(10007) << "\n"; 51 | cout << cnt_factor(8148) << "\n"; 52 | vector< pair > test = factorize(8148); 53 | for(pair entry : test) cout << entry.first << " " << entry.second << "\n"; 54 | } -------------------------------------------------------------------------------- /10. 소수의 개수 빠르게 세기/Lucy_Hedgehog.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | const ll mod = 1e9 + 7; 9 | 10 | // Lucy-Hedgehog Algorithm, O(n^3/4) 11 | // arrays with _0 : count primes 12 | // arrays with _1 : sum primes 13 | // for sum, we will deal everything with (mod 1e9+7) 14 | 15 | ll N, C; 16 | bool ispr[333333]; 17 | ll num_pr[333333], A_0[333333], B_0[333333]; 18 | ll sum_pr[333333], A_1[333333], B_1[333333]; 19 | 20 | // A keeps 1 ~ sqrt(N) 21 | // B keeps N/1 ~ N/sqrt(N) 22 | 23 | // actual dp[x] value (for counting primes) 24 | ll get_0(ll x) 25 | { 26 | if(x<=C) return A_0[x]; 27 | return B_0[N/x]; 28 | } 29 | 30 | // actual dp[x] value (for summing primes) 31 | ll get_1(ll x) 32 | { 33 | if(x<=C) return A_1[x]; 34 | return B_1[N/x]; 35 | } 36 | 37 | // 1 + 2 + ... + n = n(n+1)/2 38 | ll sum_x(ll n) 39 | { 40 | n %= mod; 41 | ll ret = (n * (n + 1)) % mod; 42 | ret = (ret * (mod + 1) / 2) % mod; 43 | return ret; 44 | } 45 | 46 | void calc_primes(void) 47 | { 48 | ll i, j; 49 | for(i=1 ; i<=C ; i++) A_0[i]=i-1; 50 | for(i=1 ; i<=C ; i++) B_0[i]=N/i-1; 51 | for(i=1 ; i<=C ; i++) A_1[i]=sum_x(i)-1; 52 | for(i=1 ; i<=C ; i++) B_1[i]=sum_x(N/i)-1; 53 | for(i=2 ; i<=C ; i++) 54 | { 55 | if(!ispr[i]) continue; 56 | for(j=1 ; j<=C ; j++) 57 | { 58 | if(N/j=1 ; j--) 64 | { 65 | if(j=mod) sum_pr[i]-=mod; 91 | } 92 | calc_primes(); 93 | cout << "Number of primes : " << get_0(N) << "\n"; 94 | cout << "Sum of primes : " << get_1(N) << "\n"; 95 | cout << fixed << setprecision(12) << "Time : " << (clock() - T) / CLOCKS_PER_SEC << "\n"; 96 | return 0; 97 | } 98 | 99 | /* 100 | 101 | Number of primes : 4118054813 102 | Sum of primes : 475146683 103 | Time : 2.392000000000 104 | 105 | */ -------------------------------------------------------------------------------- /10. 소수의 개수 빠르게 세기/Meissel_Lehmer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | // there can *definitely* be some more optimization here : left to reader 10 | // also, refer to the editorial of Codeforces' "Four Divisors" (Editorial) 11 | // Editorial uses a = pi(x^1/2) to completely remove P_2 from the equation 12 | // this code is strictly for a showcase of concept & understanding 13 | 14 | int C = 5000000; // > 10^(20/3) 15 | ll N = 10000000000LL; // 10^10 16 | 17 | vector Query[1000]; 18 | map< pair, ll> M; // computed values of phi(x, a) 19 | set< pair > vis; 20 | vector pr; 21 | ll ans; 22 | bool ispr[5000001]; // sieve 23 | int cnt_pr[5000001]; // pi(x) precompute 24 | int alive[5000001]; // for offline queries 25 | 26 | struct Fenwick 27 | { 28 | int tree[2 * 5000005]; 29 | void update(int x, int v) { while(x<=C) { tree[x]+=v; x+=(x&-x); } } 30 | int query(int x) { int ret=0; while(x) { ret+=tree[x]; x-=(x&-x); } return ret; } 31 | } T; 32 | 33 | ll P_2(ll n, ll a) 34 | { 35 | ll ret = 0; 36 | for(ll i = a+1 ; i < pr.size() && pr[i] * pr[i] <= n ; i++) 37 | ret += cnt_pr[n/pr[i]]- (i - 1); 38 | return ret; 39 | } 40 | 41 | void top_down_prep(ll n, ll a) 42 | { 43 | if(vis.count(make_pair(n, a))) return; 44 | vis.insert(make_pair(n, a)); 45 | if(a == 0) return; 46 | if(n <= C) 47 | { 48 | Query[a].push_back(n); 49 | return; 50 | } 51 | top_down_prep(n, a-1); 52 | top_down_prep(n/pr[a], a-1); 53 | } 54 | 55 | ll top_down_calc(ll n, ll a) 56 | { 57 | if(M.find(make_pair(n, a))!=M.end()) return M[make_pair(n, a)]; 58 | if(a==0) return n; 59 | return M[make_pair(n, a)] = top_down_calc(n, a-1) - top_down_calc(n/pr[a], a-1); 60 | } 61 | 62 | int main(void) 63 | { 64 | double TT = clock(); 65 | fio; ll i, j; ispr[1]=false; 66 | for(i=2 ; i<=C ; i++) ispr[i]=true; 67 | for(i=2 ; i<=C ; i++) 68 | { 69 | if(!ispr[i]) continue; 70 | for(j=2*i ; j<=C ; j+=i) ispr[j]=false; 71 | } 72 | for(i=2 ; i<=C ; i++) 73 | { 74 | cnt_pr[i]=cnt_pr[i-1]; 75 | if(ispr[i]) cnt_pr[i]++; 76 | } 77 | pr.push_back(0); // for 1-indexing 78 | for(i=2 ; i*i<=N ; i++) 79 | { 80 | if(!ispr[i]) continue; 81 | pr.push_back(i); 82 | } 83 | ll a = cnt_pr[2155]; // 2155 ~ 10^(10/3) 84 | ans += a - 1 - P_2(N, a); 85 | top_down_prep(N, a); // preparation for offline query 86 | for(i=1 ; i<=C ; i++) alive[i]=1; 87 | for(i=1 ; i<=C ; i++) T.update(i, 1); // obviously bad, you can do this in O(C) 88 | for(i=1 ; i<=a ; i++) 89 | { 90 | sort(Query[i].begin(), Query[i].end()); 91 | Query[i].erase(unique(Query[i].begin(), Query[i].end()), Query[i].end()); 92 | } 93 | for(i=1 ; i<=a ; i++) 94 | { 95 | for(j=pr[i] ; j<=C ; j+=pr[i]) 96 | if(alive[j]) T.update(j, -1), alive[j]=0; 97 | for(j=0 ; j 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | const ll mod = 1e9 + 7; 10 | 11 | /* 12 | 13 | define a multiplicative function as 14 | f(p) = p, f(p^e) = e(p+1) + 1337 for e >= 2 15 | 16 | */ 17 | 18 | // we note that for this specific example, sum_pr and precompute are exactly the same array 19 | // for more complex f(p), they will be different 20 | // for example, there will be more sum_pr arrays, and the contents will be different 21 | ll N, C; 22 | bool ispr[10111111]; 23 | int fpr[10111111]; 24 | int sum_pr[10111111]; // sum of primes 25 | int precompute[10111111]; // sum of f(p) 26 | ll A[10111111]; // for Lucy-Hedgehog step 27 | ll B[10111111]; // for Lucy-Hedgehog step 28 | vector pr; // prime vector 29 | 30 | // true dp value at x 31 | ll getv(ll x) 32 | { 33 | if(x<=C) return A[x]; 34 | return B[N/x]; 35 | } 36 | 37 | // 1 + 2 + ... + n 38 | ll sum_x(ll n) 39 | { 40 | n %= mod; 41 | ll ret = (n * (n + 1)) % mod; 42 | ret = (ret * (mod + 1) / 2) % mod; 43 | return ret; 44 | } 45 | 46 | // calculate sum of primes (for F_prime) 47 | void calc_primes(void) 48 | { 49 | ll i, j; 50 | for(i=1 ; i<=C ; i++) A[i]=sum_x(i)-1; 51 | for(i=1 ; i<=C ; i++) B[i]=sum_x(N/i)-1; 52 | for(i=2 ; i<=C ; i++) 53 | { 54 | if(!ispr[i]) continue; 55 | for(j=1 ; j<=C ; j++) 56 | { 57 | if(N/j=1 ; j--) 62 | { 63 | if(j=pr.size() || m= 1) ret-=precompute[pr[x-1]]; 103 | if(ret < 0) ret += mod; 104 | for(ll i=x ; i=m/mul+1) break; 110 | ret += f(pr[i], j+1); 111 | if(ret >= mod) ret -= mod; 112 | ret += (f(pr[i], j) * min_25(m/mul, i+1)) % mod; 113 | if(ret >= mod) ret -= mod; 114 | } 115 | } 116 | return ret % mod; 117 | } 118 | 119 | int main(void) 120 | { 121 | fio; ll i, j, ans=0; ispr[1]=false; 122 | // First, we calculate prefix sum up to 10^7 by simply sieving 123 | N = 1e7; C = (ll)(sqrt(N)); 124 | for(i=2 ; i<=N ; i++) ispr[i]=true; 125 | for(i=2 ; i<=N ; i++) 126 | { 127 | if(!ispr[i]) continue; fpr[i]=i; 128 | for(j=2*i ; j<=N ; j+=i) 129 | { 130 | if(!fpr[j]) fpr[j]=i; 131 | ispr[j]=false; 132 | } 133 | } 134 | for(i=1 ; i<=N ; i++) 135 | { 136 | ans += calc_f(i); 137 | if(ans >= mod) ans -= mod; 138 | } 139 | cout << "Answer for 1e7 : " << ans << "\n"; 140 | 141 | // Second, we will calculate the same value using min_25 sieve 142 | memset(ispr, false, sizeof(ispr)); memset(fpr, 0, sizeof(fpr)); 143 | // note : changing all C + 500 to C gives wrong answer! 144 | for(i=2 ; i<=C+500 ; i++) ispr[i]=true; 145 | for(i=2 ; i<=C+500 ; i++) 146 | { 147 | if(!ispr[i]) continue; 148 | for(j=2*i ; j<=C+500 ; j+=i) ispr[j]=false; 149 | } 150 | for(i=2 ; i<=C+500 ; i++) if(ispr[i]) pr.push_back(i); 151 | for(i=2 ; i<=C+500 ; i++) 152 | { 153 | sum_pr[i]=sum_pr[i-1]; 154 | precompute[i]=precompute[i-1]; 155 | if(!ispr[i]) continue; 156 | sum_pr[i] += i; if(sum_pr[i] >= mod) sum_pr[i] -= mod; 157 | precompute[i] += i; if(precompute[i] >= mod) precompute[i] -= mod; 158 | } 159 | calc_primes(); // run Lucy-Hedgehog 160 | cout << "Answer for 1e7 : " << min_25(N, 0) + 1 << "\n"; 161 | 162 | // Third, we will calculate prefix sum to 10^14 using min_25 sieve 163 | memset(ispr, false, sizeof(ispr)); memset(fpr, 0, sizeof(fpr)); 164 | memset(sum_pr, 0, sizeof(sum_pr)); memset(precompute, 0, sizeof(precompute)); 165 | memset(A, 0, sizeof(A)); memset(B, 0, sizeof(B)); pr.clear(); 166 | N = 1e14; C = 1e7; 167 | for(i=2 ; i<=C+500 ; i++) ispr[i]=true; 168 | for(i=2 ; i<=C+500 ; i++) 169 | { 170 | if(!ispr[i]) continue; 171 | for(j=2*i ; j<=C+500 ; j+=i) ispr[j]=false; 172 | } 173 | for(i=2 ; i<=C+500 ; i++) if(ispr[i]) pr.push_back(i); 174 | for(i=2 ; i<=C+500 ; i++) 175 | { 176 | sum_pr[i]=sum_pr[i-1]; 177 | precompute[i]=precompute[i-1]; 178 | if(!ispr[i]) continue; 179 | sum_pr[i] += i; if(sum_pr[i] >= mod) sum_pr[i] -= mod; 180 | precompute[i] += i; if(precompute[i] >= mod) precompute[i] -= mod; 181 | } 182 | 183 | double T = clock(); 184 | calc_primes(); 185 | cout << fixed << setprecision(12) << "Lucy-Hedgehog Step : " << (clock() - T) / CLOCKS_PER_SEC << " seconds!\n"; 186 | double TT = clock(); 187 | cout << "Answer for 1e14 : " << min_25(N, 0) + 1 << "\n"; 188 | cout << fixed << setprecision(12) << "Min_25 Step : " << (clock() - TT) / CLOCKS_PER_SEC << " seconds!\n"; 189 | 190 | return 0; 191 | } 192 | 193 | /* 194 | 195 | Answer for 1e7 : 479672866 196 | Answer for 1e7 : 479672866 197 | Lucy-Hedgehog Step : 327.372000000000 seconds! 198 | Answer for 1e14 : 884267024 199 | Min_25 Step : 424.646000000000 seconds! 200 | 201 | for N = 1e14, this is quite fast :) 202 | 203 | */ -------------------------------------------------------------------------------- /11. more on multiplicative functions/xudyh_sieve.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | const ll mod = 1e9 + 7; 9 | 10 | ll mem[11111], C, n; // select C ~ n^(2/3), O(n^2/3) algorithm 11 | ll prefix_f[1111111]; // prefix sum of f precomputed 12 | ll phi[1111111]; 13 | 14 | // make sure to reset array mem appropriately 15 | // NOTE : one run of getval(n) calculates ALL prefix sums for floor(n/i) values 16 | 17 | // for f = phi, we select g = 1 and (f * g)(x) = x 18 | ll prefix_g(ll x) // prefix sum of g, easily computed 19 | { 20 | return x % mod; 21 | } 22 | 23 | ll prefix_conv(ll x) // prefix sum of (f * g), easily computed 24 | { 25 | x %= mod; 26 | ll ret = (x * (x + 1)) % mod; 27 | ret = (ret * (mod + 1) / 2) % mod; 28 | return ret; 29 | } 30 | 31 | ll getval(ll x) // get prefix sum of f 32 | { 33 | if(x<=C) return prefix_f[x]; // prefix sum precomputed 34 | if(mem[n/x]!=0) return mem[n/x]; // trick - use n/x as the index to [not use map/unordered_map] 35 | ll ret=0, add; 36 | for(ll i=2, la ; i<=x ; i=la+1) 37 | { 38 | la = x/(x/i); 39 | add = prefix_g(la) - prefix_g(i-1); 40 | if(add < 0) add += mod; 41 | add = (add * getval(x/i)) % mod; 42 | ret += add; if(ret >= mod) ret -= mod; 43 | } 44 | ret = prefix_conv(x) - ret; 45 | if(ret<0) ret += mod; 46 | return mem[n/x]=ret; 47 | } 48 | 49 | int main(void) 50 | { 51 | fio; ll i, j; n = 1e9; C = 1e6; 52 | for(i=1 ; i<=C ; i++) phi[i]=i; 53 | for(i=1 ; i<=C ; i++) 54 | for(j=2*i ; j<=C ; j+=i) phi[j]-=phi[i]; 55 | // precompute prefix_f 56 | for(i=1 ; i<=C ; i++) 57 | { 58 | prefix_f[i]=prefix_f[i-1]+phi[i]; 59 | if(prefix_f[i]>=mod) prefix_f[i]-=mod; 60 | } 61 | cout << getval(n) << "\n"; 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /2. 유클리드, 확장 유클리드/README.md: -------------------------------------------------------------------------------- 1 | # 유클리드, 확장 유클리드 2 | 3 | 블로그 링크 : https://rkm0959.tistory.com/179 4 | 5 | euclidean : 유클리드 알고리즘 6 | 7 | extended_euclidean : 확장 유클리드 알고리즘 8 | 9 | ax = b (mod c) : ax == b (mod c)를 해결하는 코드 10 | -------------------------------------------------------------------------------- /2. 유클리드, 확장 유클리드/ax=b (mod c).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | ll gcd(ll a, ll b) 10 | { 11 | if(a==0) return b; // a = 0 12 | if(b==0) return a; // b = 0 13 | return gcd(b, a%b); 14 | } 15 | 16 | ll minv(ll a, ll b) // ax == 1 (mod b), assumes gcd(a, b) = 1 17 | { 18 | if(a==0 && b==1) return 0; 19 | if(a==1) return 1; // a = 1 20 | return b - minv(b%a, a) * b / a; 21 | } 22 | 23 | void solve(ll a, ll b, ll c) // solve ax == b (mod c), assumes a, c > 0, b >= 0 24 | { 25 | ll g = gcd(a, c); 26 | if(b%g!=0) 27 | { 28 | cout << "No Solutions" << "\n"; 29 | return; 30 | } 31 | a/=g; b/=g; c/=g; // now solve ax == b (mod c) 32 | ll t = minv(a, c); // at == 1 (mod c) 33 | ll sol = (t * b) % c; // multiply by b 34 | cout << "Solution : " << sol << " (mod " << c << ")\n"; 35 | } 36 | 37 | int main(void) 38 | { 39 | solve(12, 18, 54); 40 | } 41 | -------------------------------------------------------------------------------- /2. 유클리드, 확장 유클리드/euclidean.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | ll gcd(ll a, ll b) // inputs should be nonnegative 10 | { 11 | if(a==0) return b; // a = 0 12 | if(b==0) return a; // b = 0 13 | return gcd(b, a%b); 14 | } 15 | 16 | int main(void) 17 | { 18 | cout << gcd(576, 204) << "\n"; 19 | } 20 | -------------------------------------------------------------------------------- /2. 유클리드, 확장 유클리드/extended_euclidean.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | // both functions assume gcd(a, b) = 1 and positive integer inputs 10 | 11 | ll minv(ll a, ll b) // ax == 1 (mod b) 12 | { 13 | if(a==0 && b==1) return 0; 14 | if(a==1) return 1; // a = 1 15 | return b - minv(b%a, a) * b / a; 16 | } 17 | 18 | pair solve(ll a, ll b) // solution of ax + by = 1 with 0 <= x < b 19 | { 20 | if(a==0) return make_pair(0, 1); 21 | if(b==0) return make_pair(1, 0); 22 | pair prv = solve(b, a%b); 23 | ll x = ((prv.second % b) + b) % b; // x = y' mod b 24 | ll y = (1 - a * x) / b; // ax + by = 1 25 | return make_pair(x, y); 26 | } 27 | 28 | int main(void) 29 | { 30 | cout << minv(3, 7) << "\n"; 31 | pair example = solve(3, 7); 32 | cout << example.first << " " << example.second << "\n"; 33 | } 34 | -------------------------------------------------------------------------------- /3. 중국인의 나머지 정리/CRT.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | ll gcd(ll a, ll b) 10 | { 11 | if(a==0) return b; 12 | if(b==0) return a; 13 | return gcd(b, a%b); 14 | } 15 | 16 | ll minv(ll a, ll b) 17 | { 18 | if(a==0 && b==1) return 0; 19 | if(a==1) return 1; 20 | return b - minv(b%a, a) * b / a; 21 | } 22 | 23 | // x == A.first (mod A.second) 24 | // x == B.first (mod B.second) 25 | // returns solution as X == ans.first (mod ans.second) 26 | // if no solution, returns (-1, -1) 27 | // always a good idea to keep 0 <= ?.first < ?.second (for ? : A, B, ans) 28 | pair solve(pair A, pair B) 29 | { 30 | if(A.second == -1 || B.second == -1) return make_pair(-1, -1); 31 | if(A.second == 1) return B; 32 | if(B.second == 1) return A; 33 | ll g = gcd(A.second, B.second); // gcd 34 | ll l = A.second * (B.second / g); // lcm 35 | if((B.first-A.first)%g!=0) return make_pair(-1, -1); // no solution case 36 | 37 | ll a = A.second / g; 38 | ll b = B.second / g; 39 | ll mul = (B.first-A.first) / g; 40 | mul = (mul * minv(a%b, b)) % b; // this is now t 41 | ll ret = (mul * A.second + A.first); // n_1 t + a_1 42 | ret %= l; ret = (ret + l) % l; // take modulos 43 | return make_pair(ret, l); 44 | } 45 | 46 | int main(void) 47 | { 48 | pair X = solve(make_pair(2, 14), make_pair(9, 21)); 49 | cout << X.first << " " << X.second << "\n"; 50 | pair Y = solve(make_pair(3, 9), make_pair(7, 12)); 51 | cout << Y.first << " " << Y.second << "\n"; 52 | } 53 | -------------------------------------------------------------------------------- /3. 중국인의 나머지 정리/README.md: -------------------------------------------------------------------------------- 1 | # 중국인의 나머지 정리 2 | 3 | 블로그 링크 : https://rkm0959.tistory.com/180 4 | 5 | CRT : `x == a_1 (mod n_1)`, `x == a_2 (mod n_2)`를 풀어주는 코드 -------------------------------------------------------------------------------- /4. 페르마 소정리, 오일러 정리 및 활용/BOJ_13970_Power_Tower.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | // for BOJ 13970, we can achieve speedup by precomputing all phi function values 10 | 11 | ll exp(ll x, ll y, ll mod) 12 | { 13 | ll ret=1; 14 | while(y) 15 | { 16 | if(y&1) ret=(ret*x)%mod, y--; 17 | x=(x*x)%mod; y>>=1; 18 | } 19 | return ret; 20 | } 21 | 22 | // simply calculate x ** y, without mods 23 | ll power(ll x, ll y) 24 | { 25 | ll ret=1; 26 | while(y) 27 | { 28 | if(y&1) ret=ret*x, y--; 29 | x=x*x; y>>=1; 30 | } 31 | return ret; 32 | } 33 | 34 | ll phi(ll n) 35 | { 36 | ll i; ll ret=n; 37 | for(i=2 ; i*i<=n ; i++) 38 | { 39 | if(n%i==0) 40 | { 41 | ret-=ret/i; 42 | while(n%i==0) n/=i; 43 | } 44 | } 45 | if(n!=1) ret-=ret/n; 46 | return ret; 47 | } 48 | 49 | ll constrain_exp(ll x, ll y) 50 | { 51 | if(x==1 || y==0) return 1; 52 | if(x>=2 && y>=7) return 100; 53 | if(x>=3 && y>=5) return 100; 54 | if(x>=4 && y>=4) return 100; 55 | if(x>=5 && y>=3) return 100; 56 | if(x>=10 && y>=2) return 100; 57 | if(x>=100 && y>=1) return 100; 58 | return power(x, y); 59 | } 60 | 61 | ll x[1111111], n, m; 62 | 63 | ll check_large(ll st) // THIS IS O(1) 64 | { 65 | if(n-st+1>=4) return 100; // there are at least four numbers 66 | if(st==n) return x[n]; 67 | // iteratively calculate, but cap the value at 100 68 | ll val = constrain_exp(x[n-1], x[n]); 69 | for(int i=n-2 ; i>=st ; i--) val = constrain_exp(x[i], val); 70 | return val; 71 | } 72 | 73 | ll calc(ll cur, ll mod) 74 | { 75 | if(mod==1) return 0; 76 | if(cur==n) return x[n]%mod; 77 | // start to reduce problem 78 | // check [x[cur+1], ... , x[n]] is large 79 | ll cases = check_large(cur+1); 80 | if(cases >= 100) 81 | { 82 | ll next_mod = phi(mod); 83 | ll exponent = calc(cur+1, next_mod); 84 | return exp(x[cur], exponent + 100 * next_mod, mod); 85 | } 86 | else 87 | { 88 | ll next_mod = phi(mod); 89 | ll exponent = cases; 90 | return exp(x[cur], exponent, mod); 91 | } 92 | } 93 | 94 | void solve(void) 95 | { 96 | cin>>n; 97 | for(int i=1 ; i<=n ; i++) cin>>x[i]; 98 | // remove all 1s and the numbers after it 99 | for(int i=n ; i>=1 ; i--) if(x[i]==1) n=i-1; 100 | cout << (n == 0 ? 1 : calc(1, m)) << "\n"; 101 | } 102 | 103 | int main(void) 104 | { 105 | fio; int tc; cin>>tc>>m; 106 | while(tc--) solve(); 107 | } -------------------------------------------------------------------------------- /4. 페르마 소정리, 오일러 정리 및 활용/README.md: -------------------------------------------------------------------------------- 1 | # 페르마 소정리, 오일러 정리 및 활용 2 | 3 | 블로그 링크 : https://rkm0959.tistory.com/181 4 | 5 | simple_euler_phi : 오일러 파이함수를 `sqrt(n)` 시간에 계산해주는 코드 6 | 7 | BOJ_13970_Power_Tower : Power Tower 연습문제인 BOJ 13970을 해결하는 코드. -------------------------------------------------------------------------------- /4. 페르마 소정리, 오일러 정리 및 활용/simple_euler_phi.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | ll phi(ll n) 10 | { 11 | ll i; ll ret=n; 12 | for(i=2 ; i*i<=n ; i++) 13 | { 14 | if(n%i==0) 15 | { 16 | ret-=ret/i; 17 | while(n%i==0) n/=i; 18 | } 19 | } 20 | if(n!=1) ret-=ret/n; 21 | return ret; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /5. 팩토리얼과 이항계수/BOJ_14854_mod_n.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | /* 10 | 11 | note : a lot of possible speedups, since modulo is fixed as 142857 12 | ex) hardcoded CRT, arrays instead of vectors, etc.. 13 | 14 | */ 15 | 16 | int exp(int x, int y, int mod) 17 | { 18 | ll ret=1; 19 | while(y) 20 | { 21 | if(y&1) ret=(1LL*ret*x)%mod, y--; 22 | x=(1LL*x*x)%mod; y>>=1; 23 | } 24 | return ret; 25 | } 26 | 27 | int minv(int a, int b) 28 | { 29 | if(a==0 && b==1) return 0; 30 | if(a==1) return 1; 31 | return b - (1LL * minv(b%a, a) * b) / a; 32 | } 33 | 34 | pair solve(pair A, pair B) // from CRT, but g = 1 is known 35 | { 36 | int l = A.second * B.second; 37 | int mul = B.first - A.first; 38 | mul = (mul % B.second + B.second) % B.second; 39 | mul = (1LL * mul * minv(A.second, B.second)) % B.second; 40 | int ret = (1LL * mul * A.second + A.first) % l; 41 | return make_pair(ret, l); 42 | } 43 | 44 | vector< vector > factorization; 45 | vector< vector > inv; 46 | vector< vector > val; 47 | 48 | void compute_val_inv(int idx) 49 | { 50 | int p = factorization[idx][0]; 51 | int mod = factorization[idx][2]; 52 | vector cur_val(mod, 0); 53 | vector cur_inv(mod, 0); 54 | cur_val[0]=1; 55 | for(int i=1 ; i<=mod-1 ; i++) 56 | { 57 | if(i%p==0) cur_val[i]=cur_val[i-1]; 58 | else cur_val[i]=(1LL*cur_val[i-1]*i)%mod; 59 | } 60 | cur_inv[1]=1; 61 | for(int i=2 ; i<=mod-1 ; i++) 62 | { 63 | if(i%p==0) continue; 64 | cur_inv[i]=minv(i, mod); 65 | } 66 | val.push_back(cur_val); 67 | inv.push_back(cur_inv); 68 | } 69 | 70 | void precompute_everything(int mod) 71 | { 72 | for(int i=2 ; i*i<=mod ; i++) 73 | { 74 | if(mod%i==0) 75 | { 76 | int cnt=0, v=1; 77 | while(mod%i==0) { mod=mod/i; v=v*i; cnt++; } 78 | vector prime_power{i, cnt, v}; 79 | factorization.push_back(prime_power); 80 | } 81 | } 82 | if(mod!=1) 83 | { 84 | vector prime_power{mod, 1, mod}; 85 | factorization.push_back(prime_power); 86 | } 87 | for(int idx=0 ; idx factorial_p(int n, int idx) 91 | { 92 | int p = factorization[idx][0]; 93 | int mod = factorization[idx][2]; 94 | if(n V = factorial_p(k, idx); 97 | int e = V.first + k; 98 | int kp = n/mod; int rp = n%mod; 99 | int m = V.second; 100 | m = (1LL * m * exp(val[idx][mod-1], kp % 2, mod)) % mod; 101 | m = (1LL * m * val[idx][rp]) % mod; 102 | return make_pair(e, m); 103 | } 104 | 105 | int ncr_case_3_method_2(int n, int k, int idx) 106 | { 107 | int p = factorization[idx][0]; 108 | int ex = factorization[idx][1]; 109 | int mod = factorization[idx][2]; 110 | if(n<0 || k<0 || n V1 = factorial_p(n, idx); 112 | pair V2 = factorial_p(k, idx); 113 | pair V3 = factorial_p(n-k, idx); 114 | int e = V1.first - V2.first - V3.first; 115 | int m = V1.second; 116 | m = (1LL * m * inv[idx][V2.second]) % mod; 117 | m = (1LL * m * inv[idx][V3.second]) % mod; 118 | if(e >= ex) return 0; 119 | for(int i=1 ; i<=e ; i++) m = (1LL * m * p) % mod; 120 | return m; 121 | } 122 | 123 | void solve_tc(void) 124 | { 125 | int n, k; cin >> n >> k; 126 | pair cur = make_pair(0, 1); 127 | for(int idx=0 ; idx> tc; 138 | int mod = 142857; 139 | precompute_everything(mod); 140 | while(tc--) solve_tc(); 141 | return 0; 142 | } 143 | -------------------------------------------------------------------------------- /5. 팩토리얼과 이항계수/README.md: -------------------------------------------------------------------------------- 1 | # 팩토리얼과 이항계수 2 | 3 | 블로그 링크 : https://rkm0959.tistory.com/182 4 | 5 | mod_p : `(mod p)`로 팩토리얼과 이항계수를 구하는 다양한 코드. 내용은 블로그 참조. 6 | 7 | mod_p^e : `(mod p^e)`로 팩토리얼과 이항계수를 구하는 다양한 코드. 내용은 블로그 참조. 8 | 9 | mod_n : `(mod n)`으로 팩토리얼과 이항계수를 구하는 다양한 코드. 내용은 블로그 참조. 10 | 11 | BOJ_14854_mod_n : prime power로 쪼갠 후 중국인의 나머지 정리 사용하는 문제. 예시 코드. 12 | -------------------------------------------------------------------------------- /5. 팩토리얼과 이항계수/mod_n.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | ll exp(ll x, ll y, ll mod) 10 | { 11 | ll ret=1; 12 | while(y) 13 | { 14 | if(y&1) ret=(ret*x)%mod, y--; 15 | x=(x*x)%mod; y>>=1; 16 | } 17 | return ret; 18 | } 19 | 20 | bool ispr[1111111]; 21 | int fpr[1111111]; 22 | int C = 1000000; 23 | int pr_cnt[1111111]; 24 | 25 | ll mod = 1769817825; // we do not need factorization or any conditions on mod 26 | 27 | void factorize(int n, int v) // v == 1 -> numerator, v == -1 -> denominator 28 | { 29 | while(n!=1) 30 | { 31 | int p = fpr[n]; 32 | while(n%p==0) 33 | { 34 | pr_cnt[p]+=v; 35 | n/=p; 36 | } 37 | } 38 | } 39 | 40 | ll calc_ncr(int n, int k) 41 | { 42 | if(n<0 || k<0 || nn-k) k=n-k; 45 | for(int i=n-k+1 ; i<=n ; i++) factorize(i, 1); 46 | for(int i=1 ; i<=k ; i++) factorize(i, -1); 47 | for(int i=1 ; i<=n ; i++) 48 | { 49 | if(!ispr[i] || !pr_cnt[i]) continue; 50 | ret = (ret * exp(i, pr_cnt[i], mod)) % mod; 51 | } 52 | return ret; 53 | } 54 | 55 | int main(void) 56 | { 57 | int i, j; ispr[1]=false; fpr[1]=1; 58 | for(i=2 ; i<=C ; i++) ispr[i]=true; 59 | for(i=2 ; i<=C ; i++) 60 | { 61 | if(!ispr[i]) continue; fpr[i]=i; 62 | for(j=2*i ; j<=C ; j+=i) 63 | { 64 | ispr[j]=false; 65 | if(!fpr[j]) fpr[j]=i; 66 | } 67 | } 68 | int n = 678572; int k = 134865; 69 | cout << calc_ncr(n, k) << "\n"; 70 | return 0; 71 | } 72 | 73 | 74 | -------------------------------------------------------------------------------- /5. 팩토리얼과 이항계수/mod_p.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | // we assume p is a prime 10 | 11 | ll exp(ll x, ll y, ll mod) 12 | { 13 | ll ret=1; 14 | while(y) 15 | { 16 | if(y&1) ret=(ret*x)%mod, y--; 17 | x=(x*x)%mod; y>>=1; 18 | } 19 | return ret; 20 | } 21 | 22 | ll minv(ll a, ll b) 23 | { 24 | if(a==0 && b==1) return 0; 25 | if(a==1) return 1; 26 | return b - minv(b%a, a) * b / a; 27 | } 28 | 29 | ll n, p; 30 | ll inv[1111111]; // modular inverse of i 31 | ll fac[1111111]; // factorial of i 32 | ll invfac[1111111]; // modular inverse of fac[i] 33 | 34 | // we assume n < p here 35 | void topic_2_method_1(void) 36 | { 37 | fac[0]=1; invfac[0]=1; 38 | for(ll i=1 ; i<=n ; i++) 39 | { 40 | fac[i]=(fac[i-1]*i)%p; 41 | invfac[i]=minv(fac[i], p); 42 | } 43 | } 44 | 45 | // we assume n < p here 46 | void topic_2_method_2(void) 47 | { 48 | fac[0]=fac[1]=1; invfac[0]=invfac[1]=1; inv[1]=1; 49 | for(ll i=2 ; i<=n ; i++) 50 | { 51 | fac[i]=(fac[i-1]*i)%p; 52 | inv[i]=((p-p/i)*inv[p%i])%p; 53 | invfac[i]=(invfac[i-1]*inv[i])%p; 54 | } 55 | } 56 | 57 | // we assume n < p here 58 | void topic_2_method_3(void) 59 | { 60 | fac[0]=1; invfac[0]=1; 61 | for(ll i=1 ; i<=n ; i++) fac[i]=(fac[i-1]*i)%p; 62 | invfac[n]=minv(fac[n], p); 63 | for(ll i=n-1 ; i>=1 ; i--) invfac[i]=(invfac[i+1]*(i+1))%p; 64 | for(ll i=1 ; i<=n ; i++) inv[i]=(fac[i-1]*invfac[i])%p; 65 | } 66 | 67 | // returns (e, m mod p) where n! = p^e m 68 | // to use this function, we assume that we have precomputed the arrays fac, invfac for 0 <= i < p 69 | pair factorial_p(ll n) 70 | { 71 | if(n V = factorial_p(k); 74 | ll e = V.first + k; 75 | ll m = V.second; 76 | m = (m * exp(fac[p-1], k, p)) % p; // note : fac[p-1] == -1 (mod p) 77 | // therefore, to save time, we can do m = (k % 2 == 0 ? m : (p-m)); instead 78 | // or, we can simply use k % 2 instead of k as an argument in exp 79 | m = (m * fac[r]) % p; 80 | return make_pair(e, m); 81 | } 82 | 83 | ll ncr_case_1(ll n, ll k) 84 | { 85 | if(k>n-k) k=n-k; ll ret=1; 86 | for(ll i=1 ; i<=k ; i++) 87 | { 88 | ret=(ret*(n-i+1))%p; 89 | ret=(ret*minv(i, p))%p; 90 | // or, ret = (ret * inv[i]) % p if inv is computed 91 | } 92 | return ret; 93 | } 94 | 95 | // fac, invfac is computed, and n, k < p 96 | ll ncr_simple(ll n, ll k) 97 | { 98 | if(n<0 || k<0 || n V1 = factorial_p(n); 121 | pair V2 = factorial_p(k); 122 | pair V3 = factorial_p(n-k); 123 | ll e = V1.first - V2.first - V3.first; 124 | ll m = V1.second; 125 | m = (m * inv[V2.second]) % p; 126 | m = (m * inv[V3.second]) % p; 127 | if(e >= 1) return 0; 128 | return m; 129 | } 130 | -------------------------------------------------------------------------------- /5. 팩토리얼과 이항계수/mod_p^e.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | // we assume p is a prime 10 | // we work with modulus mod = p^ex 11 | 12 | ll exp(ll x, ll y, ll mod) 13 | { 14 | ll ret=1; 15 | while(y) 16 | { 17 | if(y&1) ret=(ret*x)%mod, y--; 18 | x=(x*x)%mod; y>>=1; 19 | } 20 | return ret; 21 | } 22 | 23 | ll minv(ll a, ll b) 24 | { 25 | if(a==0 && b==1) return 0; 26 | if(a==1) return 1; 27 | return b - minv(b%a, a) * b / a; 28 | } 29 | 30 | ll n, p, ex, mod; // mod = p^ex 31 | ll inv[1111111]; // modular inverse of i 32 | ll fac[1111111]; // factorial of i 33 | ll invfac[1111111]; // modular inverse of fac[i] 34 | ll val[1111111]; // val[i] from topic 3 35 | 36 | // we assume n < p here 37 | void topic_2_method_1(void) 38 | { 39 | fac[0]=1; invfac[0]=1; 40 | for(ll i=1 ; i<=n ; i++) 41 | { 42 | fac[i]=(fac[i-1]*i)%mod; 43 | invfac[i]=minv(fac[i], mod); 44 | } 45 | } 46 | 47 | // we assume n < p here 48 | void topic_2_method_3(void) 49 | { 50 | fac[0]=1; invfac[0]=1; 51 | for(ll i=1 ; i<=n ; i++) fac[i]=(fac[i-1]*i)%mod; 52 | invfac[n]=minv(fac[n], mod); 53 | for(ll i=n-1 ; i>=1 ; i--) invfac[i]=(invfac[i+1]*(i+1))%mod; 54 | for(ll i=1 ; i<=n ; i++) inv[i]=(fac[i-1]*invfac[i])%mod; 55 | } 56 | 57 | // precompute val for topic 3 58 | void topic_3_precompute(void) 59 | { 60 | val[0]=1; 61 | for(ll i=1 ; i<=mod-1 ; i++) 62 | { 63 | if(i%p==0) val[i]=val[i-1]; 64 | else val[i]=(val[i-1]*i)%mod; 65 | } 66 | } 67 | 68 | // returns (e, m mod p^ex) where n! = p^e m 69 | // to use this function, we assume that we have precomputed the arrays val for 0 <= i < p^ex 70 | pair factorial_p(ll n) 71 | { 72 | if(n V = factorial_p(k); 75 | ll e = V.first + k; 76 | ll kp = n/mod; ll rp = n%mod; 77 | ll m = V.second; 78 | // to achieve speedup, use kp % 2 instead of kp 79 | m = (m * exp(val[mod-1], kp, mod)) % mod; 80 | m = (m * val[rp]) % mod; 81 | return make_pair(e, m); 82 | } 83 | 84 | // k < p required 85 | ll ncr_case_1(ll n, ll k) 86 | { 87 | if(k>n-k) k=n-k; ll ret=1; 88 | for(ll i=1 ; i<=k ; i++) 89 | { 90 | ret=(ret*(n-i+1))%mod; 91 | ret=(ret*minv(i, mod))%mod; 92 | // or, ret = (ret * inv[i]) % mod if inv is computed 93 | } 94 | return ret; 95 | } 96 | 97 | // val is computed 98 | ll ncr_case_3_method_2(ll n, ll k) 99 | { 100 | if(n<0 || k<0 || n V1 = factorial_p(n); 102 | pair V2 = factorial_p(k); 103 | pair V3 = factorial_p(n-k); 104 | ll e = V1.first - V2.first - V3.first; 105 | ll m = V1.second; 106 | m = (m * minv(V2.second, mod)) % mod; 107 | m = (m * minv(V3.second, mod)) % mod; 108 | if(e >= ex) return 0; 109 | for(ll i=1 ; i<=e ; i++) m = (m * p) % mod; 110 | return m; 111 | } 112 | -------------------------------------------------------------------------------- /6. Miller-Rabin 소수 판별 알고리즘과 Pollard-Rho 소인수분해/BOJ_4149.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | // a lot of code chunks are taken from 10 | // https://github.com/encrypted-def/BOJ/blob/master/4149.cpp 11 | 12 | vector res; 13 | 14 | ll gcd(ll x, ll y) 15 | { 16 | if(x==0) return y; 17 | if(y==0) return x; 18 | return gcd(y, x%y); 19 | } 20 | 21 | ll extm(ll x, ll y, ll mod) 22 | { 23 | __int128 T = x; T *= y; 24 | return (ll)(T % mod); 25 | } 26 | 27 | /* 28 | 29 | ll extm(ll x, ll y, ll mod) 30 | { 31 | ll ret = 0; 32 | while(y) 33 | { 34 | if(y&1) 35 | { 36 | ret+=x; y--; 37 | if(ret>=mod) ret-=mod; 38 | } 39 | x<<=1; y>>=1; 40 | if(x>=mod) x-=mod; 41 | } 42 | return ret; 43 | } 44 | 45 | */ 46 | 47 | ll extexp(ll x, ll y, ll mod) 48 | { 49 | ll ret=1; 50 | while(y) 51 | { 52 | if(y&1) ret=extm(ret, x, mod), y--; 53 | x=extm(x, x, mod); y>>=1; 54 | } 55 | return ret; 56 | } 57 | 58 | bool trial(ll N, ll x) 59 | { 60 | if(N%x==0) return false; 61 | ll cnt=-1, d=N-1; 62 | while(d%2==0) d/=2, cnt++; 63 | ll p=extexp(x, d, N); 64 | if(p==1 || p==N-1) return true; 65 | while(cnt--) 66 | { 67 | p=extm(p, p, N); 68 | if(p==N-1) return true; 69 | } 70 | return false; 71 | } 72 | 73 | bool is_prime(ll N) 74 | { 75 | if(N==1) return false; 76 | ll tc[12]={2,3,5,7,11,13,17,19,23,29,31,37}; 77 | for(int i=0 ; i<12 ; i++) 78 | { 79 | if(N==tc[i]) return true; 80 | if(N>40 && !trial(N,tc[i])) return false; 81 | } 82 | if(N<=40) return false; 83 | return true; 84 | } 85 | 86 | ll PollardRho(ll N) 87 | { 88 | ll x=rng()%(N-2)+2; ll y=x; 89 | ll c=rng()%(N-1)+1; 90 | while(1) 91 | { 92 | x = extm(x, x, N) + c; if(x >= N) x -= N; 93 | y = extm(y, y, N) + c; if(y >= N) y -= N; 94 | y = extm(y, y, N) + c; if(y >= N) y -= N; 95 | ll d = gcd(abs(x - y), N); 96 | if(d==1) continue; 97 | if(!is_prime(d)) return PollardRho(d); 98 | else return d; 99 | } 100 | } 101 | 102 | void getFactor(ll N) 103 | { 104 | while(N%2==0) { N/=2; res.push_back(2); } 105 | while(N!=1 && !is_prime(N)) 106 | { 107 | ll d=PollardRho(N); 108 | while(N%d==0) { N/=d; res.push_back(d); } 109 | } 110 | if(N!=1) res.push_back(N); 111 | } 112 | 113 | int main(void) 114 | { 115 | fio; ll N; cin>>N; getFactor(N); 116 | sort(res.begin(), res.end()); 117 | for(int i=0 ; i 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | bool ispr[11111111]; 10 | int mu[11111111]; 11 | int C = 10000000; // sieve size 12 | 13 | // this is quite slow compared to other sols on BOJ 14 | // to optimize, learn linear sieve (optional) 15 | 16 | int main(void) 17 | { 18 | int i, j; ispr[1]=false; mu[1]=1; 19 | for(i=2 ; i<=C ; i++) ispr[i]=true, mu[i]=1; 20 | for(i=2 ; i<=C ; i++) 21 | { 22 | if(!ispr[i]) continue; mu[i]=-1; // now i is a prime 23 | for(j=2*i ; j<=C ; j+=i) // iterate over all multiples 24 | { 25 | ispr[j]=false; 26 | mu[j]=-mu[j]; // new prime i 27 | if((j/i)%i==0) mu[j]=0; // i * i is a divisor of j 28 | } 29 | } 30 | ll ans=0, a, b, c, d; 31 | cin>>a>>b>>c>>d; 32 | for(i=1 ; i<=min(b, d) ; i++) 33 | ans+=mu[i]*(b/i-(a-1)/i)*(d/i-(c-1)/i); 34 | cout< 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | // NOTE : this gives time-limit-exceeded 10 | // this is here only for demonstration purposes 11 | 12 | ll cnt[11111111]; 13 | ll a, b, c, d; 14 | 15 | int main(void) 16 | { 17 | fio; cin>>a>>b>>c>>d; ll T=min(b, d); 18 | for(ll i=1 ; i<=T ; i++) cnt[i]=(b/i-(a-1)/i)*(d/i-(c-1)/i); 19 | // cnt[i] : gcd is a multiple of i 20 | // begin "inclusion-exclusion" process 21 | for(ll i=T ; i>=1 ; i--) 22 | for(ll j=2*i ; j<=T ; j+=i) cnt[i]-=cnt[j]; 23 | cout< 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | // take modulos if you want/need 10 | 11 | // 1 : naive 12 | // 2 : after double count 13 | // 3 : sqrt technique with n/i-type values 14 | 15 | ll cnt_factor(ll n) 16 | { 17 | ll ret=0; 18 | for(ll i=1 ; i*i<=n ; i++) 19 | { 20 | if(n%i==0) 21 | { 22 | if(i*i==n) ret+=1; 23 | else ret+=2; 24 | } 25 | } 26 | return ret; 27 | } 28 | 29 | ll sum_factor(ll n) 30 | { 31 | ll ret=0; 32 | for(ll i=1 ; i*i<=n ; i++) 33 | { 34 | if(n%i==0) 35 | { 36 | if(i*i==n) ret+=i; 37 | else ret+=i+n/i; 38 | } 39 | } 40 | return ret; 41 | } 42 | 43 | ll sum_tau_1(ll n) 44 | { 45 | ll ret=0; 46 | for(ll i=1 ; i<=n ; i++) 47 | ret+=cnt_factor(i); 48 | return ret; 49 | } 50 | 51 | ll sum_tau_2(ll n) 52 | { 53 | ll ret=0; 54 | for(ll i=1 ; i<=n ; i++) 55 | ret+=n/i; 56 | return ret; 57 | } 58 | 59 | ll sum_tau_3(ll n) 60 | { 61 | ll ret=0; 62 | for(ll i=1, la ; i<=n ; i=la+1) 63 | { 64 | la=n/(n/i); // (n/i), (n/(i+1)), ... , (n/la) are all the same values 65 | ret += (la-i+1) * (n/i); // there are la - i + 1 values equal to (n/i) 66 | } 67 | return ret; 68 | } 69 | 70 | ll sum_sig_1(ll n) 71 | { 72 | ll ret=0; 73 | for(ll i=1 ; i<=n ; i++) 74 | ret+=sum_factor(i); 75 | return ret; 76 | } 77 | 78 | ll sum_sig_2(ll n) 79 | { 80 | ll ret=0; 81 | for(ll i=1 ; i<=n ; i++) 82 | ret+=i*(n/i); 83 | return ret; 84 | } 85 | 86 | ll sum_i(ll x) // 1 + 2 + ... + x 87 | { 88 | return x*(x+1)/2; 89 | } 90 | 91 | ll sum_sig_3(ll n) 92 | { 93 | ll ret=0; 94 | for(ll i=1, la ; i<=n ; i=la+1) 95 | { 96 | la=n/(n/i); // (n/i), (n/(i+1)), ... , (n/la) are all the same values 97 | ret += (sum_i(la)-sum_i(i-1)) * (n/i); // add (i + (i+1) + ... + la) * (n/i) 98 | } 99 | return ret; 100 | } 101 | 102 | int main(void) 103 | { 104 | cout << sum_tau_1(10000) << "\n"; 105 | cout << sum_tau_2(10000) << "\n"; 106 | cout << sum_tau_3(10000) << "\n"; 107 | 108 | cout << sum_sig_1(10000) << "\n"; 109 | cout << sum_sig_2(10000) << "\n"; 110 | cout << sum_sig_3(10000) << "\n"; 111 | 112 | return 0; 113 | } -------------------------------------------------------------------------------- /7. Mobius function과 그 활용/sieve_mobius.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | bool ispr[1111111]; 10 | int mu[1111111]; 11 | int C = 1000000; // sieve size 12 | 13 | int main(void) 14 | { 15 | int i, j; ispr[1]=false; mu[1]=1; 16 | for(i=2 ; i<=C ; i++) ispr[i]=true, mu[i]=1; 17 | for(i=2 ; i<=C ; i++) 18 | { 19 | if(!ispr[i]) continue; mu[i]=-1; // now i is a prime 20 | for(j=2*i ; j<=C ; j+=i) // iterate over all multiples 21 | { 22 | ispr[j]=false; 23 | mu[j]=-mu[j]; // new prime i 24 | if((j/i)%i==0) mu[j]=0; // i * i is a divisor of j 25 | } 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /8. 원시근, 이산로그, 이산제곱근/README.md: -------------------------------------------------------------------------------- 1 | # 원시근, 이산로그, 이산제곱근 2 | 3 | 블로그 링크 : https://rkm0959.tistory.com/187 4 | 5 | search_generator : order 계산 알고리즘 및 원시근 하나를 찾는 알고리즘 6 | 7 | baby_step_giant_step : discrete logarithm을 찾는 알고리즘 8 | 9 | modular_sqrt_power_of_2 : 2의 거듭제곱에 대한 modular square root 계산 알고리즘 10 | 11 | modular_sqrt_power_odd_prime : 홀수 소수의 거듭제곱에 대한 modular square root 계산 알고리즘 12 | 13 | The implementation of Pohlig-Hellman Algorithm is left as an exercise to the reader. 14 | -------------------------------------------------------------------------------- /8. 원시근, 이산로그, 이산제곱근/baby_step_giant_step.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | // BOJ 4357, but more generalizable 10 | // there can be improvements on this code, leaving that to reader 11 | 12 | ll exp(ll x, ll y, ll mod) 13 | { 14 | ll ret=1; 15 | while(y) 16 | { 17 | if(y&1) ret=(ret*x)%mod, y--; 18 | x=(x*x)%mod; y>>=1; 19 | } 20 | return ret; 21 | } 22 | 23 | ll minv(ll a, ll b) // ax == 1 (mod b) 24 | { 25 | if(a==0 && b==1) return 0; 26 | if(a==1) return 1; // a = 1 27 | return b - minv(b%a, a) * b / a; 28 | } 29 | 30 | ll phi(ll n) 31 | { 32 | ll i; ll ret=n; 33 | for(i=2 ; i*i<=n ; i++) 34 | { 35 | if(n%i==0) 36 | { 37 | ret-=ret/i; 38 | while(n%i==0) n/=i; 39 | } 40 | } 41 | if(n!=1) ret-=ret/n; 42 | return ret; 43 | } 44 | 45 | vector factorize(ll n) 46 | { 47 | vector pr; pr.clear(); 48 | for(ll i=2 ; i*i<=n ; i++) 49 | { 50 | if(n%i==0) 51 | { 52 | pr.push_back(i); 53 | while(n%i==0) n/=i; 54 | } 55 | } 56 | if(n!=1) pr.push_back(n); 57 | return pr; 58 | } 59 | 60 | ll order(ll g, ll n, ll phi_n) 61 | { 62 | vector pr=factorize(phi_n); ll ord=phi_n; 63 | for(ll i=0 ; i M; 69 | 70 | ll discrete_log(ll g, ll h, ll ord, ll n) 71 | { 72 | ll B = (ll)sqrt(ord) + 1; 73 | ll g_inv = minv(g, n); 74 | ll cur = h; 75 | for(ll i=0 ; i> n >> g >> h) 93 | { 94 | M.clear(); 95 | phi_n = phi(n); 96 | ll ord = order(g, n, phi_n); 97 | ll res = discrete_log(g, h, ord, n); 98 | if(res == -1) cout << "no solution\n"; 99 | else cout << res << "\n"; 100 | } 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /8. 원시근, 이산로그, 이산제곱근/modular_sqrt_power_odd_prime.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | ll minv(ll a, ll b) 10 | { 11 | if(a==0 && b==1) return 0; 12 | if(a==1) return 1; 13 | return b - minv(b%a, a) * b / a; 14 | } 15 | 16 | ll exp(ll x, ll y, ll mod) 17 | { 18 | ll ret=1; 19 | while(y) 20 | { 21 | if(y&1) ret=(ret*x)%mod, y--; 22 | x=(x*x)%mod; y>>=1; 23 | } 24 | return ret; 25 | } 26 | 27 | // tonelli-shanks, quite dirty code... 28 | ll tonelli_shanks(ll a, ll p) // x^2 == a (mod p) 29 | { 30 | ll Q, S=0, tp=p, cc=p-1, z, sx=0, tem; 31 | if(a==0) return 0; 32 | if(exp(a, (p-1)/2, p) != 1) return -1; // no solution 33 | if(p%4 == 3) return exp(a, (p+1)/4, p); 34 | while(cc%2==0) S++, cc/=2; Q=cc; 35 | for(z=2 ; ; z++) if(exp(z, (p-1)/2, p)!=1) break; 36 | ll M=S, c=exp(z,Q,p), t=exp(a,Q,p), R=exp(a,(Q+1)/2,p); 37 | while(1) 38 | { 39 | if(t==0) return 0; 40 | if(t==1) return R%p; 41 | sx=0; tem=t; 42 | while(1) 43 | { 44 | sx++; tem=(tem*tem)%p; 45 | if(tem==1) break; 46 | } 47 | ll b=exp(c, 1LL<<(M-sx-1), p); 48 | M=sx; c=(b*b)%p; t=(t*c)%p; R=(R*b)%p; 49 | } 50 | } 51 | 52 | // we assume p is odd prime, gcd(a, p) = 1 53 | ll modular_sqrt_power_odd(ll a, ll p, ll e) 54 | { 55 | ll r = tonelli_shanks(a, p); 56 | if(r==-1) return -1; 57 | ll cur = p; 58 | // x^2 == a (mod p^i) to x^2 == a (mod p^{i+1}) 59 | for(ll i=1 ; i<=e-1 ; i++) 60 | { 61 | ll val_1 = (2 * r) % p; 62 | ll val_2 = (a - r * r) / cur; 63 | val_2 = (val_2 % p); 64 | if(val_2 < 0) val_2 += p; 65 | ll t = (val_2 * minv(val_1, p)) % p; 66 | r += t * cur; cur = cur * p; 67 | } 68 | return r; 69 | } 70 | 71 | int main(void) 72 | { 73 | ll res = 37587681; ll p_1 = 998244353; 74 | ll t_1 = tonelli_shanks((res * res) % p_1, p_1); 75 | cout << t_1 << " " << p_1 - t_1 << "\n"; 76 | 77 | ll p_2 = 1327; ll n = p_2 * p_2 * p_2; 78 | ll t_2 = modular_sqrt_power_odd((res * res) % n, p_2, 3); 79 | cout << t_2 << " " << n - t_2 << "\n"; 80 | 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /8. 원시근, 이산로그, 이산제곱근/modular_sqrt_power_of_2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | // solve x^2 == a (mod 2^e), a is odd 10 | // we assume e >= 3, since e <= 2 is easy bruteforce 11 | // if x is returned, x, -x, x + 2^{e-1}, -x + 2^{e-1} are solutions 12 | ll modular_sqrt_pow_2(ll a, ll e) 13 | { 14 | if(a%8!=1) return -1; // no solution 15 | ll ret = 1; 16 | // move from x^2 == a (mod 2^i) to x^2 == a (mod 2^{i+1}) 17 | for(ll i=3 ; i<=e-1 ; i++) 18 | { 19 | ll stp = (1LL << (i-1)); 20 | if((ret * ret - a) % (1LL << (i + 1)) != 0) ret += stp; 21 | } 22 | assert((ret * ret - a) % (1 << e) == 0); 23 | return ret; 24 | 25 | } 26 | 27 | int main(void) 28 | { 29 | cout << modular_sqrt_pow_2(4619761, 25) << "\n"; 30 | } -------------------------------------------------------------------------------- /8. 원시근, 이산로그, 이산제곱근/search_generator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | // for n = 2, 4 : 3 is a generator of both 10 | // now assume n = p^e and we will search a generator of n 11 | // we need factorization of p-1, and here we'll use O(sqrt(p)) factorization 12 | // if p is very large, simply use Pollard-Rho for factorization 13 | 14 | vector pr; 15 | 16 | void factorize(ll n) 17 | { 18 | for(ll i=2 ; i*i<=n ; i++) 19 | { 20 | if(n%i==0) 21 | { 22 | pr.push_back(i); 23 | while(n%i==0) n/=i; 24 | } 25 | } 26 | if(n!=1) pr.push_back(n); 27 | } 28 | 29 | ll exp(ll x, ll y, ll mod) 30 | { 31 | ll ret=1; 32 | while(y) 33 | { 34 | if(y&1) ret=(ret*x)%mod, y--; 35 | x=(x*x)%mod; y>>=1; 36 | } 37 | return ret; 38 | } 39 | 40 | ll order(ll g, ll n, ll phi_n) 41 | { 42 | ll ord=phi_n; 43 | for(ll i=0 ; i= 1 49 | // searches generator of p^e 50 | // n = p^e, phi_n = p^{e-1}(p-1) 51 | ll get_generator(ll p, ll e) 52 | { 53 | ll n=1, phi_n, ord; pr.clear(); 54 | for(ll i=1 ; i<=e ; i++) n=n*p; 55 | phi_n=n-n/p; factorize(p-1); 56 | if(e>=2) pr.push_back(p); 57 | for(ll g=2 ; ; g++) 58 | { 59 | if(g==0 || g==1) continue; 60 | if(order(g, n, phi_n)==phi_n) return g; 61 | } 62 | } 63 | 64 | int main(void) 65 | { 66 | cout << get_generator(998244353, 1) << "\n"; 67 | cout << get_generator(17, 6) << "\n"; 68 | } -------------------------------------------------------------------------------- /9. 유클리드 알고리즘의 활용/Lattice_Point_Counting.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | 10 | ll get_sum(ll a, ll b) // sum a + (a-b) + ... for positive values 11 | { 12 | if(a<=0) return 0; ll z=a/b; 13 | return (z+1)*(2*a-z*b)/2; 14 | } 15 | 16 | // x, y > 0, ax + by <= c 17 | ll get_count(ll a, ll b, ll c) 18 | { 19 | if(a+b>c) return 0; 20 | if(a 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | ll ceil(ll n, ll m) { return (n+m-1)/m; } 10 | 11 | ll gcd(ll a, ll b) 12 | { 13 | if(a==0) return b; 14 | if(b==0) return a; 15 | return gcd(b, a%b); 16 | } 17 | 18 | // we assume solution exists 19 | ll solve(ll A, ll M, ll L, ll R) 20 | { 21 | if(L == 0 || L > R) return 0; 22 | if(2 * A > M) { swap(L, R); A = M - A; L = M - L; R = M - R; } 23 | ll val_1 = ceil(L, A); 24 | if(A * val_1 <= R) return val_1; 25 | ll val_2 = solve(A - M % A, A, L % A, R % A); 26 | return ceil(L + M * val_2, A); 27 | } 28 | 29 | bool sol_ex(ll A, ll M, ll L, ll R) 30 | { 31 | if(L == 0 || L > R) return true; 32 | ll g = gcd(A, M); 33 | if((L-1)/g == R/g) return false; 34 | return true; 35 | } 36 | 37 | ll brute_solve(ll A, ll M, ll L, ll R) 38 | { 39 | if(L == 0 || L > R) return 0; 40 | for(ll i=0 ; i 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | // we assume that A/B < X/Y, gcd(A, B) = 1, gcd(X, Y) = 1 10 | // we also assume that A, X, Y >= 0, B >= 1 11 | 12 | // A/B < ?/? < X/Y 13 | pair construct(ll A, ll B, ll X, ll Y) 14 | { 15 | if(A==0) return make_pair(1, Y/X+1); 16 | if(Y==0 || A/B+1 TT=construct(Y, X%Y, B, A%B); 23 | return make_pair(TT.second + (A/B) * TT.first, TT.first); 24 | } -------------------------------------------------------------------------------- /9. 유클리드 알고리즘의 활용/Modulo_Maximization_Minimization.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 3 | using namespace std; 4 | typedef long long int ll; 5 | typedef unsigned long long int ull; 6 | typedef long double ldb; 7 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 8 | 9 | ll ceil(ll n, ll m) { return (n+m-1)/m; } 10 | 11 | ll gcd(ll a, ll b) 12 | { 13 | if(a==0) return b; 14 | if(b==0) return a; 15 | return gcd(b, a%b); 16 | } 17 | 18 | // binary search + Linear Inequality with Modulo 19 | ll solve(ll A, ll M, ll L, ll R) 20 | { 21 | if(L == 0 || L > R) return 0; 22 | if(2 * A > M) { swap(L, R); A = M - A; L = M - L; R = M - R; } 23 | ll val_1 = ceil(L, A); 24 | if(A * val_1 <= R) return val_1; 25 | ll val_2 = solve(A - M % A, A, L % A, R % A); 26 | return ceil(L + M * val_2, A); 27 | } 28 | 29 | bool sol_ex(ll A, ll M, ll L, ll R) 30 | { 31 | if(L == 0 || L > R) return true; 32 | ll g = gcd(A, M); 33 | if((L-1)/g == R/g) return false; 34 | return true; 35 | } 36 | 37 | // rq (mod m) min for 1 <= q <= c 38 | ll min_rem_bs(ll r, ll m, ll c) 39 | { 40 | r = r % m; 41 | if(c < 1) return 1e18; // failure 42 | if(r == 0) return 0; 43 | ll cyc = m / gcd(m, r); 44 | if(c >= cyc) return 0; 45 | ll lef = 1, rig = m-1, mid, best; 46 | while(lef <= rig) 47 | { 48 | mid = (lef + rig) >> 1; 49 | if(sol_ex(r, m, 1, mid) && solve(r, m, 1, mid) <= c) best = mid, rig = mid - 1; 50 | else lef = mid + 1; 51 | } 52 | return best; 53 | } 54 | 55 | // rq (mod m) max for 1 <= q <= c 56 | ll max_rem_bs(ll r, ll m, ll c) 57 | { 58 | r = r % m; 59 | if(r == 0 || c <= m / r) return r * c; 60 | ll cyc = m / gcd(m, r); 61 | if(c >= cyc) return m - gcd(m, r); 62 | return m - min_rem_bs(m-r, m, c); 63 | } 64 | 65 | ll min_rem_brute(ll r, ll m, ll c) 66 | { 67 | ll ret = m; 68 | for(ll i=1 ; i<=c ; i++) ret = min(ret, (r * i) % m); 69 | return ret; 70 | } 71 | 72 | ll max_rem_brute(ll r, ll m, ll c) 73 | { 74 | ll ret = 0; 75 | for(ll i=1 ; i<=c ; i++) ret = max(ret, (r * i) % m); 76 | return ret; 77 | } 78 | 79 | int main(void) 80 | { 81 | ll it = 300000; 82 | while(it--) 83 | { 84 | ll m = rng() % 100000000 + 100000; 85 | ll r = rng() % 100000000 + 100000; 86 | ll c = rng() % 100000 + 10000; 87 | ll res_1 = min_rem_bs(r, m, c); 88 | ll res_2 = min_rem_brute(r, m, c); 89 | ll res_3 = max_rem_bs(r, m, c); 90 | ll res_4 = max_rem_brute(r, m, c); 91 | assert(res_1 == res_2 && res_3 == res_4); 92 | } 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /9. 유클리드 알고리즘의 활용/README.md: -------------------------------------------------------------------------------- 1 | # 유클리드 알고리즘의 활용 2 | 3 | 블로그 링크 : https://rkm0959.tistory.com/188 4 | 5 | Lattice_Point_Counting : `x, y > 0, ax + by <= c` 격자점 개수 세기, `floor((a+bk)/c)` 합 구하기 6 | 7 | Linear_Inequality_with_Modulo : `L <= Ax (mod M) <= R` 최소 해 구하기 8 | 9 | Modulo_Maximization_Minimization : `Ax (mod M)` 을 `1 <= x <= C` 조건에서 최소화 10 | 11 | Minimal_Fraction : `A/B < ?/? < X/Y`를 만족하는 "minimal"한 분수 구하기 12 | 13 | 14 | 15 | TODO : Modulo_Maximization_Minimization의 `O(log n)` 구현체 추가 (adamant가 수정하면...) 16 | 17 | 현재는 Modulo_Maximization_Minimization이 `O(log^2 n)`으로 구현됨 (이분탐색 방식) 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Number_Theory_in_CP_PS 2 | CP, PS에서 등장하는 정수론을 위한 가이드 3 | 4 | Introduction : https://rkm0959.tistory.com/177 5 | 6 | 후기, post-mortem : https://rkm0959.tistory.com/191 7 | 8 | 백준 문제집 : 6593번 ~ 6603번 9 | --------------------------------------------------------------------------------