Related
I should implement this summation in C ++. I have tried with this code, but with very high numbers up to 10 ^ 12 it takes too long.
The summation is:
For any positive integer k, let d(k) denote the number of positive divisors of k (including 1 and k itself).
For example, for the number 4: 1 has 1 divisor, 2 has two divisors, 3 has two divisors, and 4 has three divisors. So the result would be 8.
This is my code:
#include <iostream>
#include <algorithm>
using namespace std;
int findDivisors(long long n)
{
int c=0;
for(int j=1;j*j<=n;j++)
{
if(n%j==0)
{
c++;
if(j!=(n/j))
{
c++;
}
}
}
return c;
}
long long compute(long long n)
{
long long sum=0;
for(int i=1; i<=n; i++)
{
sum += (findDivisors(i));
}
return sum;
}
int main()
{
int n, divisors;
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
cin >> n;
cout << compute(n);
}
I think it's not just a simple optimization problem, but maybe I should change the algorithm entirely.
Would anyone have any ideas to speed it up? Thank you.
largest_prime_is_463035818's answer shows an O(N) solution, but the OP is trying to solve this problem
with very high numbers up to 1012.
The following is an O(N1/2) algorithm, based on some observations about the sum
n/1 + n/2 + n/3 + ... + n/n
In particular, we can count the number of terms with a specific value.
Consider all the terms n/k where k > n/2. There are n/2 of those and all are equal to 1 (integer division), so that their sum is n/2.
Similar considerations hold for the other dividends, so that we can write the following function
long long count_divisors(long long n)
{
auto sum{ n };
for (auto i{ 1ll }, k_old{ n }, k{ n }; i < k ; ++i, k_old = k)
{ // ^^^^^ it goes up to sqrt(n)
k = n / (i + 1);
sum += (k_old - k) * i;
if (i == k)
break;
sum += k;
}
return sum;
}
Here it is tested against the O(N) algorithm, the only difference in the results beeing the corner cases n = 0 and n = 1.
Edit
Thanks again to largest_prime_is_463035818, who linked the Wikipedia page about the divisor summatory function, where both an O(N) and an O(sqrt(N)) algorithm are mentioned.
An implementation of the latter may look like this
auto divisor_summatory(long long n)
{
auto sum{ 0ll };
auto k{ 1ll };
for ( ; k <= n / k; ++k )
{
sum += n / k;
}
--k;
return 2 * sum - k * k;
}
They also add this statement:
Finding a closed form for this summed expression seems to be beyond the techniques available, but it is possible to give approximations. The leading behavior of the series is given by
D(x) = xlogx + x(2γ - 1) + Δ(x)
where γ is the Euler–Mascheroni constant, and the error term is Δ(x) = O(sqrt(x)).
I used your brute force approach as reference to have test cases. The ones I used are
compute(12) == 35
cpmpute(100) == 482
Don't get confused by computing factorizations. There are some tricks one can play when factorizing numbers, but you actually don't need any of that. The solution is a plain simple O(N) loop:
#include <iostream>
#include <limits>
long long compute(long long n){
long long sum = n+1;
for (long long i=2; i < n ; ++i){
sum += n/i;
}
return sum;
}
int main()
{
std::cout << compute(12) << "\n";
std::cout << compute(100) << "\n";
}
Output:
35
482
Why does this work?
The key is in Marc Glisse's comment:
As often with this kind of problem, this sum actually counts pairs x,
y where x divides y, and the sum is arranged to count first all x
corresponding to a fixed y, but nothing says you have to keep it that
way.
I could stop here, because the comment already explains it all. Though, if it didn't click yet...
The trick is to realize that it is much simpler to count divisors of all numbers up to n rather than n-times counting divisors of individual numbers and take the sum.
You don't need to care about factorizations of eg 123123123 or 52323423 to count all divisors up to 10000000000. All you need is a change of perspective. Instead of trying to factorize numbers, consider the divisors. How often does the divisor 1 appear up to n? Simple: n-times. How often does the divisor 2 appear? Still simple: n/2 times, because every second number is divisible by 2. Divisor 3? Every 3rd number is divisible by 3. I hope you can see the pattern already.
You could even reduce the loop to only loop till n/2, because bigger numbers obviously appear only once as divisor. Though I didn't bother to go further, because the biggest change is from your O(N * sqrt(N)) to O(N).
Let's start off with some math and reduce the O(n * sq(n)) factorization to O(n * log(log(n))) and for counting the sum of divisors the overall complexity is O(n * log(log(n)) + n * n^(1/3)).
For instance:
In Codeforces himanshujaju explains how we can optimize the solution of finding divisors of a number.
I am simplifying it a little bit.
Let, n as the product of three numbers p, q, and r.
so assume p * q * r = n, where p <= q <= r.
The maximum value of p = n^(1/3).
Now we can loop over all prime numbers in a range [2, n^(1/3)]
and try to reduce the time complexity of prime factorization.
We will split our number n into two numbers x and y => x * y = n.
And x contains prime factors up to n^(1/3) and y deals with higher prime factors greater than n^(1/3).
Thus gcd(x, y) = 1.
Now define F(n) as the number of prime factors of n.
From multiplicative rules, we can say that
F(x * y) = F(x) * F(y), if gcd(x, y) = 1.
For finding F(n) => F(x * y) = F(x) * F(y)
So first find F(x) then F(y) will F(n/x)
And there will 3 cases to cover for y:
1. y is a prime number: F(y) = 2.
2. y is the square of a prime number: F(y) = 3.
3. y is a product of two distinct prime numbers: F(y) = 4.
So once we are done with finding F(x) and F(y), we are also done with finding F(x * y) or F(n).
In Cp-Algorithm there is also a nice explanation of how to count the number of divisors on a number. And also in GeeksForGeeks a nice coding example of how to count the number of divisors of a number in an efficient way. One can check the articles and can generate a nice solution to this problem.
C++ implementation
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 11;
bool prime[maxn];
bool primesquare[maxn];
int table[maxn]; // for storing primes
void SieveOfEratosthenes()
{
for(int i = 2; i < maxn; i++){
prime[i] = true;
}
for(int i = 0; i < maxn; i++){
primesquare[i] = false;
}
// 1 is not a prime number
prime[1] = false;
for(int p = 2; p * p < maxn; p++){
// If prime[p] is not changed, then
// it is a prime
if(prime[p] == true){
// Update all multiples of p
for(int i = p * 2; i < maxn; i += p){
prime[i] = false;
}
}
}
int j = 0;
for(int p = 2; p < maxn; p++) {
if (prime[p]) {
// Storing primes in an array
table[j] = p;
// Update value in primesquare[p * p],
// if p is prime.
if(p < maxn / p) primesquare[p * p] = true;
j++;
}
}
}
// Function to count divisors
int countDivisors(int n)
{
// If number is 1, then it will have only 1
// as a factor. So, total factors will be 1.
if (n == 1)
return 1;
// ans will contain total number of distinct
// divisors
int ans = 1;
// Loop for counting factors of n
for(int i = 0;; i++){
// table[i] is not less than cube root n
if(table[i] * table[i] * table[i] > n)
break;
// Calculating power of table[i] in n.
int cnt = 1; // cnt is power of prime table[i] in n.
while (n % table[i] == 0){ // if table[i] is a factor of n
n = n / table[i];
cnt = cnt + 1; // incrementing power
}
// Calculating the number of divisors
// If n = a^p * b^q then total divisors of n
// are (p+1)*(q+1)
ans = ans * cnt;
}
// if table[i] is greater than cube root of n
// First case
if (prime[n])
ans = ans * 2;
// Second case
else if (primesquare[n])
ans = ans * 3;
// Third case
else if (n != 1)
ans = ans * 4;
return ans; // Total divisors
}
int main()
{
SieveOfEratosthenes();
int sum = 0;
int n = 5;
for(int i = 1; i <= n; i++){
sum += countDivisors(i);
}
cout << sum << endl;
return 0;
}
Output
n = 4 => 8
n = 5 => 10
Complexity
Time complexity: O(n * log(log(n)) + n * n^(1/3))
Space complexity: O(n)
Thanks, #largest_prime_is_463035818 for pointing out my mistake.
I have a problem:
You are given a sequence, in the form of a string with characters ‘0’, ‘1’, and ‘?’ only. Suppose there are k ‘?’s. Then there are 2^k ways to replace each ‘?’ by a ‘0’ or a ‘1’, giving 2^k different 0-1 sequences (0-1 sequences are sequences with only zeroes and ones).
For each 0-1 sequence, define its number of inversions as the minimum number of adjacent swaps required to sort the sequence in non-decreasing order. In this problem, the sequence is sorted in non-decreasing order precisely when all the zeroes occur before all the ones. For example, the sequence 11010 has 5 inversions. We can sort it by the following moves: 11010 →→ 11001 →→ 10101 →→ 01101 →→ 01011 →→ 00111.
Find the sum of the number of inversions of the 2^k sequences, modulo 1000000007 (10^9+7).
For example:
Input: ??01
-> Output: 5
Input: ?0?
-> Output: 3
Here's my code:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <math.h>
using namespace std;
void ProcessSequences(char *input)
{
int c = 0;
/* Count the number of '?' in input sequence
* 1??0 -> 2
*/
for(int i=0;i<strlen(input);i++)
{
if(*(input+i) == '?')
{
c++;
}
}
/* Get all possible combination of '?'
* 1??0
* -> ??
* -> 00, 01, 10, 11
*/
int seqLength = pow(2,c);
// Initialize 2D array of integer
int **sequencelist, **allSequences;
sequencelist = new int*[seqLength];
allSequences = new int*[seqLength];
for(int i=0; i<seqLength; i++){
sequencelist[i] = new int[c];
allSequences[i] = new int[500000];
}
//end initialize
for(int count = 0; count < seqLength; count++)
{
int n = 0;
for(int offset = c-1; offset >= 0; offset--)
{
sequencelist[count][n] = ((count & (1 << offset)) >> offset);
// cout << sequencelist[count][n];
n++;
}
// cout << std::endl;
}
/* Change '?' in former sequence into all possible bits
* 1??0
* ?? -> 00, 01, 10, 11
* -> 1000, 1010, 1100, 1110
*/
for(int d = 0; d<seqLength; d++)
{
int seqCount = 0;
for(int e = 0; e<strlen(input); e++)
{
if(*(input+e) == '1')
{
allSequences[d][e] = 1;
}
else if(*(input+e) == '0')
{
allSequences[d][e] = 0;
}
else
{
allSequences[d][e] = sequencelist[d][seqCount];
seqCount++;
}
}
}
/*
* Sort each sequences to increasing mode
*
*/
// cout<<endl;
int totalNum[seqLength];
for(int i=0; i<seqLength; i++){
int num = 0;
for(int j=0; j<strlen(input); j++){
if(j==strlen(input)-1){
break;
}
if(allSequences[i][j] > allSequences[i][j+1]){
int temp = allSequences[i][j];
allSequences[i][j] = allSequences[i][j+1];
allSequences[i][j+1] = temp;
num++;
j = -1;
}//endif
}//endfor
totalNum[i] = num;
}//endfor
/*
* Sum of all Num of Inversions
*/
int sum = 0;
for(int i=0;i<seqLength;i++){
sum = sum + totalNum[i];
}
// cout<<"Output: "<<endl;
int out = sum%1000000007;
cout<< out <<endl;
} //end of ProcessSequences method
int main()
{
// Get Input
char seq[500000];
// cout << "Input: "<<endl;
cin >> seq;
char *p = &seq[0];
ProcessSequences(p);
return 0;
}
the results were right for small size input, but for bigger size input I got time CPU time limit > 1 second. I also got exceeded memory size. How to make it faster and optimal memory use? What algorithm should I use and what better data structure should I use?, Thank you.
Dynamic programming is the way to go. Imagine You are adding the last character to all sequences.
If it is 1 then You get XXXXXX1. Number of swaps is obviously the same as it was for every sequence so far.
If it is 0 then You need to know number of ones already in every sequence. Number of swaps would increase by the amount of ones for every sequence.
If it is ? You just add two previous cases together
You need to calculate how many sequences are there. For every length and for every number of ones (number of ones in the sequence can not be greater than length of the sequence, naturally). You start with length 1, which is trivial, and continue with longer. You can get really big numbers, so You should calculate modulo 1000000007 all the time. The program is not in C++, but should be easy to rewrite (array should be initialized to 0, int is 32bit, long in 64bit).
long Mod(long x)
{
return x % 1000000007;
}
long Calc(string s)
{
int len = s.Length;
long[,] nums = new long[len + 1, len + 1];
long sum = 0;
nums[0, 0] = 1;
for (int i = 0; i < len; ++i)
{
if(s[i] == '?')
{
sum = Mod(sum * 2);
}
for (int j = 0; j <= i; ++j)
{
if (s[i] == '0' || s[i] == '?')
{
nums[i + 1, j] = Mod(nums[i + 1, j] + nums[i, j]);
sum = Mod(sum + j * nums[i, j]);
}
if (s[i] == '1' || s[i] == '?')
{
nums[i + 1, j + 1] = nums[i, j];
}
}
}
return sum;
}
Optimalization
The code above is written to be as clear as possible and to show dynamic programming approach. You do not actually need array [len+1, len+1]. You calculate column i+1 from column i and never go back, so two columns are enough - old and new. If You dig more into it, You find out that row j of new column depends only on row j and j-1 of the old column. So You can go with one column if You actualize the values in the right direction (and do not overwrite values You would need).
The code above uses 64bit integers. You really need that only in j * nums[i, j]. The nums array contain numbers less than 1000000007 and 32bit integer is enough. Even 2*1000000007 can fit into 32bit signed int, we can make use of it.
We can optimize the code by nesting loop into conditions instead of conditions in the loop. Maybe it is even more natural approach, the only downside is repeating the code.
The % operator is, as every dividing, quite expensive. j * nums[i, j] is typically far smaller that capacity of 64bit integer, so we do not have to do modulo in every step. Just watch the actual value and apply when needed. The Mod(nums[i + 1, j] + nums[i, j]) can also be optimized, as nums[i + 1, j] + nums[i, j] would always be smaller than 2*1000000007.
And finally the optimized code. I switched to C++, I realized there are differences what int and long means, so rather make it clear:
long CalcOpt(string s)
{
long len = s.length();
vector<long> nums(len + 1);
long long sum = 0;
nums[0] = 1;
const long mod = 1000000007;
for (long i = 0; i < len; ++i)
{
if (s[i] == '1')
{
for (long j = i + 1; j > 0; --j)
{
nums[j] = nums[j - 1];
}
nums[0] = 0;
}
else if (s[i] == '0')
{
for (long j = 1; j <= i; ++j)
{
sum += (long long)j * nums[j];
if (sum > std::numeric_limits<long long>::max() / 2) { sum %= mod; }
}
}
else
{
sum *= 2;
if (sum > std::numeric_limits<long long>::max() / 2) { sum %= mod; }
for (long j = i + 1; j > 0; --j)
{
sum += (long long)j * nums[j];
if (sum > std::numeric_limits<long long>::max() / 2) { sum %= mod; }
long add = nums[j] + nums[j - 1];
if (add >= mod) { add -= mod; }
nums[j] = add;
}
}
}
return (long)(sum % mod);
}
Simplification
Time limit still exceeded? There is probably better way to do it. You can either
get back to the beginning and find out mathematically different way to calculate the result
or simplify actual solution using math
I went the second way. What we are doing in the loop is in fact convolution of two sequences, for example:
0, 0, 0, 1, 4, 6, 4, 1, 0, 0,... and 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,...
0*0 + 0*1 + 0*2 + 1*3 + 4*4 + 6*5 + 4*6 + 1*7 + 0*8...= 80
The first sequence is symmetric and the second is linear. It this case, the sum of convolution can be calculated from sum of the first sequence which is = 16 (numSum) and number from second sequence corresponding to the center of the first sequence, which is 5 (numMult). numSum*numMult = 16*5 = 80. We replace the whole loop with one multiplication if we are able to update those numbers in each step, which fortulately seems the case.
If s[i] == '0' then numSum does not change and numMult does not change.
If s[i] == '1' then numSum does not change, only numMult increments by 1, as we shift the whole sequence by one position.
If s[i] == '?' we add original and shiftet sequence together. numSum is multiplied by 2 and numMult increments by 0.5.
The 0.5 means a bit problem, as it is not the whole number. But we know, that the result would be whole number. Fortunately in modular arithmetics in this case exists inversion of two (=1/2) as a whole number. It is h = (mod+1)/2. As a reminder, inversion of 2 is such a number, that h*2=1 modulo mod. Implementation wisely it is easier to multiply numMult by 2 and divide numSum by 2, but it is just a detail, we would need 0.5 anyway. The code:
long CalcOptSimpl(string s)
{
long len = s.length();
long long sum = 0;
const long mod = 1000000007;
long numSum = (mod + 1) / 2;
long long numMult = 0;
for (long i = 0; i < len; ++i)
{
if (s[i] == '1')
{
numMult += 2;
}
else if (s[i] == '0')
{
sum += numSum * numMult;
if (sum > std::numeric_limits<long long>::max() / 4) { sum %= mod; }
}
else
{
sum = sum * 2 + numSum * numMult;
if (sum > std::numeric_limits<long long>::max() / 4) { sum %= mod; }
numSum = (numSum * 2) % mod;
numMult++;
}
}
return (long)(sum % mod);
}
I am pretty sure there exists some simple way to get this code, yet I am still unable to see it. But sometimes path is the goal :-)
If a sequence has N zeros with indexes zero[0], zero[1], ... zero[N - 1], the number of inversions for it would be (zero[0] + zero[1] + ... + zero[N - 1]) - (N - 1) * N / 2. (you should be able to prove it)
For example, 11010 has two zeros with indexes 2 and 4, so the number of inversions would be 2 + 4 - 1 * 2 / 2 = 5.
For all 2^k sequences, you can calculate the sum of two parts separately and then add them up.
1) The first part is zero[0] + zero[1] + ... + zero[N - 1]. Each 0 in the the given sequence contributes index * 2^k and each ? contributes index * 2^(k-1)
2) The second part is (N - 1) * N / 2. You can calculate this using a dynamic programming (maybe you should google and learn this first). In short, use f[i][j] to present the number of sequence with j zeros using the first i characters of the given sequence.
So, I started learning C++ recently. This code is trying to add the sum of the squares of each numbers digits. For example: 243: 2*2 + 4*4 + 3*3 = 29.
int sumOfSquareDigits(int n) //BUG WITH INPUT OF 10, 100, 1000, etc.
{
int digits = findDigits(n);
int number;
int remainder;
int *allDigits = new int[digits];
for (int i = 0; i < digits; i++) { //assigns digits to array
if (i + 1 == digits){ //sees if there is a ones value left
allDigits[i] = n;
}
else {
remainder = (n % findPower10(digits - (i + 1)));
number = ((n - remainder) / findPower10(digits - (i + 1)));
allDigits[i] = number; //records leftmost digit
n = n - (allDigits[i] * findPower10(digits - (i + 1))); //gets rid of leftmost number and starts over
}
}
int result = 0;
for (int i = 0; i < digits; i++) { //finds sum of squared digits
result = result + (allDigits[i] * allDigits[i]);
}
delete [] allDigits;
return result;
}
int findDigits(int n) //finds out how many digits the number has
{
int digits = 0;
int test;
do {
digits++;
test = findPower10(digits);
} while (n > test);
return digits;
}
int findPower10(int n) { //function for calculating powers of 10
int result = 1;
for (int i = 0; i < n; i++)
result = result * 10;
return result;
}
And after running the code, I've figured out that it (barely) mostly works. I've found that whenever a user inputs a value of 10, 100, 1000, etc. it always returns a value of 100. I'd like to solve this only using the iostream header.
Sorry if my code isn't too readable or organized! It would also be helpful if there are any shortcuts to my super long code, thanks!
The problem is in the findDigits function. For the values 10, 100, 1000 etc, it calculates the number of the digits minus one. This happens because of the comparison in the loop, you are stopping when n is less or equal to test, but in these cases n is equal test and you should run the next iteration.
So, you should change the line 33:
} while (n > test);
to:
} while (n >= test);
Now, it should work just fine. But it will not work for negative numbers (I don't know this is required, but the solution bellow works for that case too).
I came up with a much simpler solution:
int sumOfSquareDigits(int n)
{
// Variable to mantain the total sum of the squares
int sum = 0;
// This loop will change n until it is zero
while (n != 0) {
/// The current digit we will calculate the square is the rightmost digit,
// so we just get its value using the mod operator
int current = n % 10;
// Add its square to the sum
sum += current*current;
// You divide n by 10, this 'removes' one digit of n
n = n / 10;
}
return sum;
}
I found the problem challenging managed to reduce your code to the following lines:
long long sumOfSquareDigits(long long i) {
long long sum(0L);
do {
long long r = i % 10;
sum += (r * r);
} while(i /= 10);
return sum;
}
Haven't test it thoroughly but I think it works OK.
The problem is to find the n-th Catalan number mod m, where m is NOT prime, m = (10^14 + 7). Here are the list of methods that I have tried: (max N = 10,000)
Dynamic programming for table look-up, too slow
Use Catalan formula ncr(2*n, n)/(n + 1), again it wasn't fast enough due to the ncr function, can't speed up using exponentiation squaring because m is not prime.
Hardcode a table of pre-generated Catalans, but it failed due to the file size limit.
Recurrence relation C(i,k) = C(i-1,k-1) + C(i-1,k), this is way too slow
So I wonder is there any other faster algorithm to find the n-th Catalan number that I'm not aware of?
Using Dynamic Programming
void generate_catalan_numbers() {
catalan[1] = 1;
for (int i = 2; i <= MAX_NUMBERS; i++) {
for (int j = 1; j <= i - 1; j++) {
catalan[i] = (catalan[i] + ((catalan[j]) * catalan[i - j]) % MODULO) % MODULO;
}
catalan[i] = catalan[i] % MODULO;
}
}
Using original formula
ull n_choose_r(ull n, ull r) {
if (n < r)
return 0;
if (r > n/2) {
r = n - r;
}
ull result = 1;
ull common_divisor;
for (int i = 1; i <= r; ++i) {
common_divisor = gcd(result, i);
result /= common_divisor;
result *= (n - i + 1) / (i / common_divisor);
}
return result;
}
Using recurrence relation
ull n_choose_r_relation(ull n, ull r) {
for (int i = 0; i <= n + 1; ++i) {
for (int k = 0; k <= r && k <= i; ++k) {
if (k == 0 || k == i) {
ncr[i][k] = 1;
}
else {
ncr[i][k] = (ncr[i - 1][k - 1] + ncr[i - 1][k]) % MODULO;
}
}
}
return ncr[n][r];
}
From an answer I wrote just as this question about computation of nCr got closed, which ended up in the comments instead:
I'm not sure this is the absolute fastest, but it should be efficient enough. The key is that modulo multiplication decomposes, but division doesn't, so one first must reduce the fraction, as follows:
Since n <= 10000, it's very possible to build an array of size 2*n.
Use the Sieve of Eratosthenes to find and store pairs of factors for all composite numbers up to 20000). This step only needs to be done once regardless of how many Catalan numbers are to be calculated.
Make another table of size 2*n which represents the exponent of each factor.
Now, iterate the product in the Catalan formula .
Break each factor into prime factors using the sieve table, incrementing the exponent table for each term in the numerator and decrementing it for each term in the denominator.
No entry will ever end up negative.
Now, use modulo arithmetic to multiply together the non-cancelled factors.
No division operations are required at any point. Nor any fractions.
Demonstration of my method applied to multi-nCr: http://ideone.com/Weeg6
To use this for Catalan numbers, you can use this instead of the loops inside calc_combinations:
for( unsigned k = 2; k <= N; ++k ) {
factor<+1>(k+N);
factor<-1>(k);
}
The code then looks like this: http://ideone.com/ZZApk
Solution
#include <utility>
#include <vector>
std::vector< std::pair<int, int> > factor_table;
void fill_sieve( int n )
{
factor_table.resize(n+1);
for( int i = 1; i <= n; ++i )
factor_table[i] = std::pair<int, int>(i, 1);
for( int j = 2, j2 = 4; j2 <= n; (j2 += j), (j2 += ++j) ) {
if (factor_table[j].second == 1) {
int i = j;
int ij = j2;
while (ij <= n) {
factor_table[ij] = std::pair<int, int>(j, i);
++i;
ij += j;
}
}
}
}
std::vector<unsigned> powers;
template<int dir>
void factor( int num )
{
while (num != 1) {
powers[factor_table[num].first] += dir;
num = factor_table[num].second;
}
}
void calc_catalan(unsigned N)
{
powers.resize(0);
powers.resize(2*N+1);
for( unsigned k = 2; k <= N; ++k ) {
factor<+1>(k+N);
factor<-1>(k);
}
}
Test Driver
#include <iostream>
#include <cmath>
int main(void)
{
fill_sieve(20000);
unsigned N = 9913;
unsigned long long M = 1000000000007LL;
calc_catalan(N);
unsigned long long result = 1;
for( unsigned i = 0; i < powers.size(); ++i ) {
while (powers[i]--) {
result *= i;
result %= M;
}
}
std::cout << "Catalan(" << N << ") modulo " << M << " = " << result << "\n\n";
}
Completed demo: http://ideone.com/FDWfB
Here's another related question, which I answered with code and demonstration: Number of combinations (N choose R) in C++
Easy, peasy. Compute the prime factors of the binomial coefficient. A simple task using a sieve. I won't get into the rest of it, but a powermod computation is trivial, and you don't even need a divide.
For N = 10000, I get 42224403014400 in short order.
But, if you want the full number itself, the 10000'th Catalan number itself is ...
22453781249338521563359358425736057870110358621936588777329371383585
443658870053449099810271911432021020990539379958970114932732650095370271
397751300183876130693653440780258549445459994177372998459176454278220288
679699783327649549651476024591222065426709156831181207130089121989402216
517545144106669143509197596949973192167548893412063804651413496597406903
967719298471463870452875276986356795262033484770727452974197655810423629
386184662262278329466750526865120502476640878488187299740404235631962632
335108916990663560351330901464515744357084282208286669901241545533951877
777078174205283779947690623035078595904048715811899275348402286537327410
009576296851062523691528014340846065120667839872568170381150542379156626
173532955062796771718993285598391346886779480658586379448386923993317934
139425945651509102645665277040984870211604644540699508509248821099873225
565699224344151993874742555422872473424262356666363196825449089721410665
537521519676271082500130505509387186351879731113568837096419481746389018
721284533242225719341420124434480886444987373634542567071582458263380247
628252179873943804465262216365735901268165347321451279736504798992232739
106390706179212626442096326217616178171108663008963682821183764312867791
507672494716865305031842633900748973827504534625795968537648004286087039
823233370550650634239448544304798764239028734674653967478032618882557954
859328131980782727940394400855369003385513208814011609977239377877068501
893633819436630205358663340684840462204867552576509569736390978718963517
869423927523718504671005747648411794527978689778762460237949479732242725
154275831263823307362585789708343583184171797113785187466609433767144371
710845773715328364171910363978492352051901370003068055356444233141131383
192077598317531370925033378421138581148001529316546340657631162629562941
211065221871760353772365014435796695284269667873562415761642871681276498
507492541421942131281008978510862112693424595990036710403533420006771490
575482785612280198742983770649313043583275207213939274300662039637048647
395250014477941359641726047221826652916778311801541491816826072282488555
018173563867058868251361080516013361134986419403377613243853586312008767
909635869692823359899687030213634793656744420820912530014968355236934193
747181786083577435923400955703014812335311495073521773651461701750485101
119310472898683618090898735223665962918372501660743711042258315604294195
583076309209507444333462531858856911411408798540404888967120239682480627
570158137868956844950713279360385273144560292399045892610118082102910880
862332337854786916935223744892537176357434650161037841572213751901947447
479406915511862629144757855890852243043614898752155191154178797427659170
858428903659564218086017881546286273599385917718058276038925354040884258
022546721698832195059172836919416429064599278227491956109630837263590884
232587058023101145921693423507849076470763334833613166731358258440439729
023251976962577737416518794914009277934381234511794730677137605309953636
716963188964230436087118746073758080815722286112796870306754227017546055
347853334923811143440952672436342961180384459596879312187164969968096364
679341577416027452001090523659332406246454292701122715894579618818643071
139925009651888661718404932582731927646801878919152052218535889565319288
284306134970608577076704660104569794464663831193002735423564364371354521
236158069405955372080665906666149641642367693009585743888230289135078928
729184475260174446278915850624301208853693618442212023236924456444468934
014289741543223145235333811594418344798647068944904371005158995839127368
111629241573877617157577569590584624720552246920280151741755137476154967
741272080362312952750328628775530857638646138592895858764915987201920286
661490154786097488396300779244279606416541720716707237058679072236693234
932525387774462125138686406910133757255779021404876020200833761157767584
015369673586027681003369474431448843539054790848335705489738731700240579
310855452462903455809888697753847348175077261616431384533713924568807999
599683993362082982833949280082553659996487889394727840889035163412693106
865702752400579571351436509808650503057036278511515529330634352096987240
087618010503197530225589878764240330302768263496958673020211712107611762
945771002810537812467742009399047607169797035466100221770262334445478074
080845928677855301631860443068261061887109865290453732333638130446973519
286828584088203627113605849939106943614542645022903932947597417823646592
053417189520415596451505598330301782369213897762201629272201936584136036
027455748892667375417522206148332891409959866390232031014358337935412166
499617373308661369292739138448626161089231445046384163766705419698533262
040353901193260661841441922949263756492472641127072018961101915467728184
640938751407261817683231072132781927769994322689591991504965204544928105
747119997826784396172488376877215547707335474490892399544875233372674064
229287210750045834971802632275569822679385098328070604595140732389126327
092826465756212595551194678295464565601548041854366455751504169209131794
100099734293551231149329072243438440125013340293416345726479426178738686
238273833019523777019099811511419301476900607138083408535229058593795242
998150989330379630607152057165593682028276808657989133687600036850256257
973833780907105126134335912174477305526445570101413725539992976023375381
201759604514592679113676113078381084050224814280307372001545194100603017
219283437543128615425515965977881708976796492254901456997277712672653778
789696887633779923567912536882486775488103616173080561347127863398147885
811314120272830343521897029277536628882920301387371334992369039412492040
272569854478601604868543152581104741474604522753521632753090182704058850
525546680379379188800223157168606861776429258407513523623704438333489387
460217759660297923471793682082742722961582765796049294605969530190679149
426065241142453853283673009798518752237906836442958353267589634936329512
043142900668824981800672231156890228835045258196841806861681826866706774
199447245550164975361170844597908233890221446745462710788815648943858461
7793175431865532382711812960546611287516640
The sequence of triangle numbers is
generated by adding the natural
numbers. So the 7th triangle number
would be 1 + 2 + 3 + 4 + 5 + 6 + 7 =
28. The first ten terms would be:
1, 3, 6, 10, 15, 21, 28, 36, 45, 55,
...
Let us list the factors of the first
seven triangle numbers:
1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
We can see that 28 is the first
triangle number to have over five
divisors.
Given an integer n, display the first
triangle number having at least n
divisors.
Sample Input: 5
Output 28
Input Constraints: 1<=n<=320
I was obviously able to do this question, but I used a naive algorithm:
Get n.
Find triangle numbers and check their number of factors using the mod operator.
But the challenge was to show the output within 4 seconds of input. On high inputs like 190 and above it took almost 15-16 seconds. Then I tried to put the triangle numbers and their number of factors in a 2d array first and then get the input from the user and search the array. But somehow I couldn't do it: I got a lot of processor faults. Please try doing it with this method and paste the code. Or if there are any better ways, please tell me.
Here's a hint:
The number of divisors according to the Divisor function is the product of the power of each prime factor plus 1. For example, let's consider the exponential prime representation of 28:
28 = 22 * 30 * 50 * 71 * 110...
The product of each exponent plus one is: (2+1)*(0+1)*(0+1)*(1+1)*(0+1)... = 6, and sure enough, 28 has 6 divisors.
Now, consider that the nth triangular number can be computed in closed form as n(n+1)/2. We can multiply numbers written in the exponential prime form simply by adding up the exponents at each position. Dividing by two just means decrementing the exponent on the two's place.
Do you see where I'm going with this?
Well, you don't go into a lot of detail about what you did, but I can give you an optimization that can be used, if you didn't think of it...
If you're using the straightforward method of trying to find factors of a number n, by using the mod operator, you don't need to check all the numbers < n. That obviously would take n comparisons...you can just go up to floor(sqrt(n)). For each factor you find, just divide n by that number, and you'll get the conjugate value, and not need to find it manually.
For example: say n is 15.
We loop, and try 1 first. Yep, the mod checks out, so it's a factor. We divide n by the factor to get the conjugate value, so we do (15 / 1) = 15...so 15 is a factor.
We try 2 next. Nope. Then 3. Yep, which also gives us (15 / 3) = 5.
And we're done, because 4 is > floor(sqrt(n)). Quick!
If you didn't think of it, that might be something you could leverage to improve your times...overall you go from O(n) to O(sqrt (n)) which is pretty good (though for numbers this small, constants may still weigh heavily.)
I was in a programming competition way back in school where there was some similar question with a run time limit. the team that "solved" it did as follows:
1) solve it with a brute force slow method.
2) write a program to just print out the answer (you found using the slow method), which will run sub second.
I thought this was bogus, but they won.
see Triangular numbers: a(n) = C(n+1,2) = n(n+1)/2 = 0+1+2+...+n. (Formerly M2535 N1002)
then pick the language you want implement it in, see this:
"... Python
import math
def diminishing_returns(val, scale):
if val < 0:
return -diminishing_returns(-val, scale)
mult = val / float(scale)
trinum = (math.sqrt(8.0 * mult + 1.0) - 1.0) / 2.0
return trinum * scale
..."
First, create table with two columns: Triangle_Number Count_of_Factors.
Second, derive from this a table with the same columns, but consisting only of the 320 rows of the lowest triangle number with a distinct number of factors.
Perform your speedy lookup to the second table.
If you solved the problem, you should be able to access the thread on Project Euler in which people post their (some very efficient) solutions.
If you're going to copy and paste a problem, please cite the source (unless it was your teacher who stole it); and I second Wouter van Niferick's comment.
Well, at least you got a good professor. Performance is important.
Since you have a program that can do the job, you can precalculate all of the answers for 1 .. 320.
Store them in an array, then simply subscript into the array to get the answer. That will be very fast.
Compile with care, winner of worst code of the year :D
#include <iostream>
bool isPrime( unsigned long long number ){
if( number != 2 && number % 2 == 0 )
return false;
for( int i = 3;
i < static_cast<unsigned long long>
( sqrt(static_cast<double>(number)) + 1 )
; i += 2 ){
if( number % i == 0 )
return false;
}
return true;
}
unsigned int p;
unsigned long long primes[1024];
void initPrimes(){
primes[0] = 2;
primes[1] = 3;
unsigned long long number = 5;
for( unsigned int i = 2; i < 1024; i++ ){
while( !isPrime(number) )
number += 2;
primes[i] = number;
number += 2;
}
return;
}
unsigned long long nextPrime(){
unsigned int ret = p;
p++;
return primes[ret];
}
unsigned long long numOfDivs( unsigned long long number ){
p = 0;
std::vector<unsigned long long> v;
unsigned long long prime = nextPrime(), divs = 1, i = 0;
while( number >= prime ){
i = 0;
while( number % prime == 0 ){
number /= prime;
i++;
}
if( i )
v.push_back( i );
prime = nextPrime();
}
for( unsigned n = 0; n < v.size(); n++ )
divs *= (v[n] + 1);
return divs;
}
unsigned long long nextTriNumber(){
static unsigned long long triNumber = 1, next = 2;
unsigned long long retTri = triNumber;
triNumber += next;
next++;
return retTri;
}
int main()
{
initPrimes();
unsigned long long n = nextTriNumber();
unsigned long long divs = 500;
while( numOfDivs(n) <= divs )
n = nextTriNumber();
std::cout << n;
std::cin.get();
}
def first_triangle_number_with_over_N_divisors(N):
n = 4
primes = [2, 3]
fact = [None, None, {2:1}, {3:1}]
def num_divisors (x):
num = 1
for mul in fact[x].values():
num *= (mul+1)
return num
while True:
factn = {}
for p in primes:
if p > n//2: break
r = n // p
if r * p == n:
factn = fact[r].copy()
factn[p] = factn.get(p,0) + 1
if len(factn)==0:
primes.append(n)
factn[n] = 1
fact.append(factn)
(x, y) = (n-1, n//2) if n % 2 == 0 else (n, (n-1)//2)
numdiv = num_divisors(x) * num_divisors(y)
if numdiv >= N:
print('Triangle number %d: %d divisors'
%(x*y, numdiv))
break
n += 1
>>> first_triangle_number_with_over_N_divisors(500)
Triangle number 76576500: 576 divisors
Dude here is ur code, go have a look. It calculates the first number that has divisors greater than 500.
void main() {
long long divisors = 0;
long long nat_num = 0;
long long tri_num = 0;
int tri_sqrt = 0;
while (1) {
divisors = 0;
nat_num++;
tri_num = nat_num + tri_num;
tri_sqrt = floor(sqrt((double)tri_num));
long long i = 0;
for ( i=tri_sqrt; i>=1; i--) {
long long remainder = tri_num % i;
if ( remainder == 0 && tri_num == 1 ) {
divisors++;
}
else if (remainder == 0 && tri_num != 1) {
divisors++;
divisors++;
}
}
if (divisors >100) {
cout <<"No. of divisors: "<<divisors<<endl<<tri_num<<endl;
}
if (divisors > 500)
break;
}
cout<<"Final Result: "<<tri_num<<endl;
system("pause");
}
Boojum's answer motivated me to write this little program. It seems to work well, although it does use a brute force method of computing primes. It's neat how all the natural numbers can be broken down into prime number components.
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <iomanip>
#include <vector>
//////////////////////////////////////////////////////////////////////////////
typedef std::vector<size_t> uint_vector;
//////////////////////////////////////////////////////////////////////////////
// add a prime number to primes[]
void
primeAdd(uint_vector& primes)
{
size_t n;
if (primes.empty())
{
primes.push_back(2);
return;
}
for (n = *(--primes.end()) + 1; ; ++n)
{
// n is even -> not prime
if ((n & 1) == 0) continue;
// look for a divisor in [2,n)
for (size_t i = 2; i < n; ++i)
{
if ((n % i) == 0) continue;
}
// found a prime
break;
}
primes.push_back(n);
}
//////////////////////////////////////////////////////////////////////////////
void
primeFactorize(size_t n, uint_vector& primes, uint_vector& f)
{
f.clear();
for (size_t i = 0; n > 1; ++i)
{
while (primes.size() <= i) primeAdd(primes);
while (f.size() <= i) f.push_back(0);
while ((n % primes[i]) == 0)
{
++f[i];
n /= primes[i];
}
}
}
//////////////////////////////////////////////////////////////////////////////
int
main(int argc, char** argv)
{
// allow specifying number of TN's to be evaluated
size_t lim = 1000;
if (argc > 1)
{
lim = atoi(argv[1]);
}
if (lim == 0) lim = 1000;
// prime numbers
uint_vector primes;
// factors of (n), (n + 1)
uint_vector* f = new uint_vector();
uint_vector* f1 = new uint_vector();
// sum vector
uint_vector sum;
// prime factorize (n)
size_t n = 1;
primeFactorize(n, primes, *f);
// iterate over triangle-numbers
for (; n <= lim; ++n)
{
// prime factorize (n + 1)
primeFactorize(n + 1, primes, *f1);
while (f->size() < f1->size()) f->push_back(0);
while (f1->size() < f->size()) f1->push_back(0);
size_t numTerms = f->size();
// compute prime factors for (n * (n + 1) / 2)
sum.clear();
size_t i;
for (i = 0; i < numTerms; ++i)
{
sum.push_back((*f)[i] + (*f1)[i]);
}
--sum[0];
size_t numFactors = 1, tn = 1;
for (i = 0; i < numTerms; ++i)
{
size_t exp = sum[i];
numFactors *= (exp + 1);
while (exp-- != 0) tn *= primes[i];
}
std::cout
<< n << ". Triangle number "
<< tn << " has " << numFactors << " factors."
<< std::endl;
// prepare for next iteration
f->clear();
uint_vector* tmp = f;
f = f1;
f1 = tmp;
}
delete f;
delete f1;
return 0;
}