Combinatorics - The Candies - c++

I found this problem somewhere in a contest and haven't been able to come up with a solution yet.
The boy has apples and keeps in boxes. In one box no more than N/2.
How many methods he can put candies to boxes.
So what I'm trying to do is to implement solution using DP. Here is my code:
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <unistd.h>
#include <vector>
#define size 1002
using namespace std;
long long a[size][size];
int n, k;
int main()
{
cin >> n >> k;
int kk = n/2;
for(int i = 0; i <= k; ++i)
a[0][i] = 1;
a[0][0] = 0;
for(int i = 0; i <= kk; ++i)
a[i][1] = 1;
for(int i = 1; i <= n; ++i) {
for(int j = 2; j <= k; ++j) {
int index = 0;
long long res = 0;
while(1) {
res += a[i-index][j - 1];
index += 1;
if(index == kk + 1 || i-index < 0)
break;
}
a[i][j] = res;
}
}
cout << a[n][k] << endl;
}
But the problem is that we have large numbers in input like:
2 ≤ N ≤ 1000 is a quantity of the candies, N - even; 2 ≤ S ≤ 1000 - is a quantity of small boxes.
So, for input like N = 1000 and S = 1000, I have to spent 5*10^8 operations. And the numbers are very big, so I have to use BigInteger arithmetics?
Maybe there is algorithm to implement the problem in linear time? Thanks and sorry for my English!

You can easily decrease the time complexity from O(kn^2) into O(nk) by the following observation:
for(int i = 1; i <= n; ++i) {
for(int j = 2; j <= k; ++j) {
int index = 0;
long long res = 0;
while(1) {
res += a[i-index][j - 1];
index += 1;
if(index == kk + 1 || i-index < 0)
break;
}
a[i][j] = res;
}
}
for each a[i][j], we can easily see that
a[i][j] = sum a[k][j - 1] with k from (i - n/2) to i
So, if we create an array sum to store the sum from all indexes of the previous step, we can reduce one for loop from the above nested loop
a[i][j] = sum[i] - sum[i - (n/2) - 1];
Pseudo code:
long long sum[n + 1];
for(int j = 2; j <= k; ++j) {
long long nxt[n + 1];
for(int i = 1; i <= n; ++i) {
int index = 0;
long long res = sum[i] - sum[i - (n/2) - 1];
a[i][j] = res;
nxt[i] = nxt[i - 1] + a[i][j];//Prepare the sum array for next step
}
sum = nxt;
}
Note: This above code is not handled the initialization step for array sum, as well as not handle the case when i < n/2. Those cases should be obvious to handle.
Update:
My below Java solution get accepted by using similar idea:
public static void main(String[] args) throws FileNotFoundException {
// PrintWriter out = new PrintWriter(new FileOutputStream(new File(
// "output.txt")));
PrintWriter out = new PrintWriter(System.out);
Scanner in = new Scanner();
int n = in.nextInt();
int s = in.nextInt();
BigInteger[][] dp = new BigInteger[n + 1][2];
BigInteger[][] count = new BigInteger[2][n + 1];
int cur = 1;
for (int i = 0; i <= n / 2; i++) {
dp[i][0] = BigInteger.ONE;
count[0][i] = (i > 0 ? count[0][i - 1] : BigInteger.ZERO)
.add(dp[i][0]);
}
for (int i = n / 2 + 1; i <= n; i++) {
dp[i][0] = BigInteger.ZERO;
count[0][i] = count[0][i - 1];
}
for (int i = 2; i <= s; i++) {
for (int j = 0; j <= n; j++) {
dp[j][cur] = dp[j][1 - cur].add((j > 0 ? count[1 - cur][j - 1]
: BigInteger.ZERO)
.subtract(j > n / 2 ? count[1 - cur][j - (n / 2) - 1]
: BigInteger.ZERO));
count[cur][j] = (j > 0 ? count[cur][j - 1] : BigInteger.ZERO)
.add(dp[j][cur]);
}
cur = 1 - cur;
}
out.println(dp[n][1 - cur]);
out.close();
}

Related

Dynamic dice sum - modulo

You have d dice, and each die has f faces numbered 1, 2, ..., f.
Return the number of possible ways (out of fd total ways) modulo 10^9 + 7 to roll the dice so the sum of the face up numbers equals target.
My code works well for small values of f,d and target. It gives 0 as answer for big values say 30, 30, 500.
I am getting a lot of difficulty solving where modulo occurs.
What is wrong with my solution ?
int numRollsToTarget(int d, int f, int target)
{
long long int dp[d][target];
for (int i = 0; i < d; i++)
{
for (int j = 0; j < target; j++)
{
dp[i][j] = 0;
}
}
for (int i = 0; i < f && i < target; i++)
{
dp[0][i] = 1;
}
for (int i = 1; i < d; i++)
{
for (int j = 0; j < target; j++)
{
if (j >= i)
for (int k = max(0, j - f); k < min(j, f); k++)
dp[i][j] = (dp[i - 1][j - k - 1] % 1000000007 +
dp[i][j] % 1000000007) % 1000000007;
}
}
return dp[d - 1][target - 1];
}

prime number index position c program

#include <stdio.h>
#include <bitset>
using namespace std;
short smallprimes[549]; // about 1100 bytes
char in[19531]; // almost 20k
int isprime(int j) {
if (j < 3)
return j == 2;
for (int i = 0; i < 549; i++) {
int p = smallprimes[i];
if (p * p > j)
break;
if (!(j % p))
return 0;
}
return 1;
}
void init() {
bitset<4000> siv;
for (int i = 2; i < 64; i++)
if (!siv[i])
for (int j = i + i; j < 4000; j += i)
siv[j] = 1;
int k = 0;
for (int i = 3; i < 4000; i += 2)
if (!siv[i]) {
smallprimes[k++] = i;
}
for (int a0 = 0; a0 < 10000000; a0 += 512) {
in[a0 / 512] = !a0;
for (int j = a0 + 1; j < a0 + 512; j += 2)
in[a0 / 512] += isprime(j);
}
}
int whichprime(int k) {
if (k == 2)
return 1;
int a = k / 512;
int ans = 1 + !a;
for (int i = 0; i < a; i++)
ans += in[i];
for (int i = a * 512 + 1; i < k; i += 2)
ans += isprime(i);
return ans;
}
int main() {
int k;
init();
while (1 == scanf("%i", &k))
printf("%i\n", whichprime(k));
}
This is my code. It shows the index value of the prime number in an array.
I want small code which can get index value of prime numbers store in an array. Or I enter a prime number and then program calculates prime number at that particular index and shows its index position.
Input: 2
Output: 1 (index in an array)
It's quite complicated. Looking for an alternate solution.
Here's my less complicated (fewer magic numbers) generic C approach to this problem. Like the OP's original code, it produces bad results if passed non-primes to index:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
typedef unsigned long PRIME;
bool *primes;
size_t calloc_size = 3;
void sieve(PRIME end) {
if (end >= calloc_size) {
primes = realloc(primes, end + 1);
memset(primes + calloc_size, true, end - calloc_size + 1);
calloc_size = end + 1;
}
// This might be optimized to not resieve old territory ...
for (size_t i = 0; i <= end; i++) {
if (primes[i]) {
for (size_t j = i * 2; j <= end; j += i) {
primes[j] = false;
}
}
}
}
// whichprime() returns 1-based index of target prime in primes array.
// Current and future results are indeterminate if argument isn't prime.
size_t whichprime(PRIME prime) {
if (prime < calloc_size) {
for (size_t i = 0, idx = 0; i < calloc_size; i++) {
if (primes[i]) {
idx++;
if (i == prime) {
return idx; // Target prime already in primes array
}
}
}
assert(false); // should never be reached
}
sieve(prime);
return whichprime(prime); // recurse as we now know it's in primes
}
int main() {
PRIME k;
// This could be optimized to not store even numbers ..
primes = calloc(calloc_size, sizeof(bool));
primes[calloc_size - 1] = true;
while (1 == scanf("%lu", &k)) {
printf("%lu\n", whichprime(k));
}
free(primes);
return 0;
}
The boolean primes array is a sieve that gets extended as needed.
USAGE
> ./a.out
2999
430
859433
68301
13
6
7919
1000
>

C++ Sub sequence Exercise

I was assigned a "project" where I should create a C++ program to find the largest possible sum of two sub sequences. The user inputs N (array length), K (length of each sub sequence) and N numbers representing the array. The two sub sequences can touch but can't override each other e.g. 1 5 20 20 20 15 10 1 1 1 should output 90 ((5+20+20)+(20+15_10)) and not 115 ((20+20+20)+(20+20+15)).
My code until now is:
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int N, K, MaxN;
cin >> N;
cin >> K;
int Pi[N];
MaxN = N - K + 1;
int Word[MaxN];
int MaxSum;
for(int nn=0; nn<N; nn++) {
cin >> Pi[nn];
}
for(int y=0;y<MaxN;y++) {
Word[y] = 0;
}
for(int j=0; j<MaxN; j++) {
for(int l=0; l<K; l++) {
Word[j] = Word[j] + Pi[j+l];
}
}
sort(Word, Word + MaxN);
MaxSum = Word[MaxN-2] + Word[MaxN-1];
cout << MaxSum;
return 0;
}
Which is correct only in the case where the 2 sub sequences don't interfere with each other e.g. in an array such as 2 4 15 12 10 1 1 20 4 10 which outputs 71.
Thank you all in advance.
This is solution:
precalculate prefixes and suffixes
iterate end of the first subarray
iterate begin of the second subarray, but start from the end of first sub. ar. + 1
we have sum of numbers on interval from 0 to *end* = prefix[end], but we are interested only in interval [end - k, k], so simply subtract prefix[end] - prefix[end - k - 1]
[0 .. end-k-1, end-k .. end]
The same approach for the second subarray: sum2 = suffix[begin] - suffix[begin + i + 1]
then compare with the previous answer
So we just brute-force all possible sub-arrays which not intersect and find the max their sum
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int N,K,MaxN;
cin >> N;
cin >> K;
int Pi[N];
MaxN=N-K+1;
int Word[MaxN];
int MaxSum;
for(int nn=0;nn<N;nn++){
cin >> Pi[nn];
}
int prefix[N];
int sufix[N];
for (int i = 0; i < N; i++) {
prefix[i] = sufix[i] = 0;
}
for (int i = 0; i < N; i++) {
if (i == 0)
prefix[i] = Pi[i];
else
prefix[i] = Pi[i] + prefix[i - 1];
}
for (int i = N - 1; i >= 0; i--) {
if (i == N - 1)
sufix[i] = Pi[i];
else
sufix[i] = Pi[i] + sufix[i + 1];
}
int ans = 0;
for (int i = K - 1; i < MaxN; i++) {
for (int j = i + 1; j < MaxN; j++) {
int x = prefix[i] - (i - K >= 0 ? prefix[i - K] : 0);
int y = sufix[j] - (j + K < N ? sufix[j + K] : 0);
ans = max(ans, x + y);
}
}
cout << ans;
return 0;
}

Find a subarray of m*m (2<=m<n) having largest sum; out of an n*n int array(having +ve, -ve, 0s)

I have written a solution for the above problem but can someone please suggest an optimized way.
I have traversed through the array for count(2 to n) where count is finding subarrays of size count*count.
int n = 5; //Size of array, you may take a dynamic array as well
int a[5][5] = {{1,2,3,4,5},{2,4,7,-2,1},{4,3,9,9,1},{5,2,6,8,0},{5,4,3,2,1}};
int max = 0;
int **tempStore, size;
for(int count = 2; count < n; count++)
{
for(int i = 0; i <= (n-count); i++)
{
for(int j = 0; j <= (n-count); j++)
{
int **temp = new int*[count];
for(int i = 0; i < count; ++i) {
temp[i] = new int[count];
}
for(int k = 0; k < count; k++)
{
for(int l = 0; l <count; l++)
{
temp[k][l] = a[i+k][j+l];
}
}
//printing fetched array
int sum = 0;
for(int k = 0; k < count; k++)
{
for(int l = 0; l <count; l++)
{
sum += temp[k][l];
cout<<temp[k][l]<<" ";
}cout<<endl;
}cout<<"Sum = "<<sum<<endl;
if(sum > max)
{
max = sum;
size = count;
tempStore = new int*[count];
for(int i = 0; i < count; ++i) {
tempStore[i] = new int[count];
}
//Locking the max sum array
for(int k = 0; k < count; k++)
{
for(int l = 0; l <count; l++)
{
tempStore[k][l] = temp[k][l];
}
}
}
//printing finished
cout<<"------------------\n";
//Clear temp memory
for(int i = 0; i < size; ++i) {
delete[] temp[i];
}
delete[] temp;
}
}
}
cout<<"Max sum is = "<<max<<endl;
for(int k = 0; k < size; k++)
{
for(int l = 0; l <size; l++)
{
cout<<tempStore[k][l]<<" ";
}cout<<endl;
}cout<<"-------------------------";
//Clear tempStore memory
for(int i = 0; i < size; ++i) {
delete[] tempStore[i];
}
delete[] tempStore;
Example:
1 2 3 4 5
2 4 7 -2 1
4 3 9 9 1
5 2 6 8 0
5 4 3 2 1
Output:
Max sum is = 71
2 4 7 -2
4 3 9 9
5 2 6 8
5 4 3 2
This is a problem best solved using Dynamic Programming (DP) or memoization.
Assuming n is significantly large, you will find that recalculating the sum of every possible combination of matrix will take too long, therefore if you could reuse previous calculations that would make everything much faster.
The idea is to start with the smaller matrices and calculate sum of the larger one reusing the precalculated value of the smaller ones.
long long *sub_solutions = new long long[n*n*m];
#define at(r,c,i) sub_solutions[((i)*n + (r))*n + (c)]
// Winner:
unsigned int w_row = 0, w_col = 0, w_size = 0;
// Fill first layer:
for ( int row = 0; row < n; row++) {
for (int col = 0; col < n; col++) {
at(r, c, 0) = data[r][c];
if (data[r][c] > data[w_row][w_col]) {
w_row = r;
w_col = c;
}
}
}
// Fill remaining layers.
for ( int size = 1; size < m; size++) {
for ( int row = 0; row < n-size; row++) {
for (int col = 0; col < n-size; col++) {
long long sum = data[row+size][col+size];
for (int i = 0; i < size; i++) {
sum += data[row+size][col+i];
sum += data[row+i][col+size];
}
sum += at(row, col, size-1); // Reuse previous solution.
at(row, col, size) = sum;
if (sum > at(w_row, w_col, w_size)) { // Could optimize this part if you only need the sum.
w_row = row;
w_col = col;
w_size = size;
}
}
}
}
// The largest sum is of the sub_matrix starting a w_row, w_col, and has dimensions w_size+1.
long long largest = at(w_row, w_col, w_size);
delete [] sub_solutions;
This algorithm has complexity: O(n*n*m*m) or more precisely: 0.5*n*(n-1)*m*(m-1). (Now I haven't tested this so please let me know if there are any bugs.)
Try this one (using naive approach, will be easier to get the idea):
#include <iostream>
#include<vector>
using namespace std;
int main( )
{
int n = 5; //Size of array, you may take a dynamic array as well
int a[5][5] =
{{2,1,8,9,0},{2,4,7,-2,1},{5,4,3,2,1},{3,4,9,9,2},{5,2,6,8,0}};
int sum, partsum;
int i, j, k, m;
sum = -999999; // presume minimum part sum
for (i = 0; i < n; i++) {
partsum = 0;
m = sizeof(a[i])/sizeof(int);
for (j = 0; j < m; j++) {
partsum += a[i][j];
}
if (partsum > sum) {
k = i;
sum = partsum;
}
}
// print subarray having largest sum
m = sizeof(a[k])/sizeof(int); // m needs to be recomputed
for (j = 0; j < m - 1; j++) {
cout << a[k][j] << ", ";
}
cout << a[k][m - 1] <<"\nmax part sum = " << sum << endl;
return 0;
}
With a cumulative sum, you may compute partial sum in constant time
std::vector<std::vector<int>>
compute_cumulative(const std::vector<std::vector<int>>& m)
{
std::vector<std::vector<int>> res(m.size() + 1, std::vector<int>(m.size() + 1));
for (std::size_t i = 0; i != m.size(); ++i) {
for (std::size_t j = 0; j != m.size(); ++j) {
res[i + 1][j + 1] = m[i][j] - res[i][j]
+ res[i + 1][j] + res[i][j + 1];
}
}
return res;
}
int compute_partial_sum(const std::vector<std::vector<int>>& cumulative, std::size_t i, std::size_t j, std::size_t size)
{
return cumulative[i][j] + cumulative[i + size][j + size]
- cumulative[i][j + size] - cumulative[i + size][j];
}
live example

Can anyone explain this algorithm for calculating large factorials?

i came across the following program for calculating large factorials(numbers as big as 100).. can anyone explain me the basic idea used in this algorithm??
I need to know just the mathematics implemented in calculating the factorial.
#include <cmath>
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
unsigned int d;
unsigned char *a;
unsigned int j, n, q, z, t;
int i,arr[101],f;
double p;
cin>>n;
p = 0.0;
for(j = 2; j <= n; j++)
p += log10(j);
d = (int)p + 1;
a = new unsigned char[d];
for (i = 1; i < d; i++)
a[i] = 0; //initialize
a[0] = 1;
p = 0.0;
for (j = 2; j <= n; j++)
{
q = 0;
p += log10(j);
z = (int)p + 1;
for (i = 0; i <= z/*NUMDIGITS*/; i++)
{
t = (a[i] * j) + q;
q = (t / 10);
a[i] = (char)(t % 10);
}
}
for( i = d -1; i >= 0; i--)
cout << (int)a[i];
cout<<"\n";
delete []a;
return 0;
}
Note that
n! = 2 * 3 * ... * n
so that
log(n!) = log(2 * 3 * ... * n) = log(2) + log(3) + ... + log(n)
This is important because if k is a positive integer then the ceiling of log(k) is the number of digits in the base-10 representation of k. Thus, these lines of code are counting the number of digits in n!.
p = 0.0;
for(j = 2; j <= n; j++)
p += log10(j);
d = (int)p + 1;
Then, these lines of code allocate space to hold the digits of n!:
a = new unsigned char[d];
for (i = 1; i < d; i++)
a[i] = 0; //initialize
Then we just do the grade-school multiplication algorithm
p = 0.0;
for (j = 2; j <= n; j++) {
q = 0;
p += log10(j);
z = (int)p + 1;
for (i = 0; i <= z/*NUMDIGITS*/; i++) {
t = (a[i] * j) + q;
q = (t / 10);
a[i] = (char)(t % 10);
}
}
The outer loop is running from j from 2 to n because at each step we will multiply the current result represented by the digits in a by j. The inner loop is the grade-school multiplication algorithm wherein we multiply each digit by j and carry the result into q if necessary.
The p = 0.0 before the nested loop and the p += log10(j) inside the loop just keep track of the number of digits in the answer so far.
Incidentally, I think there is a bug in this part of the program. The loop condition should be i < z not i <= z otherwise we will be writing past the end of a when z == d which will happen for sure when j == n. Thus replace
for (i = 0; i <= z/*NUMDIGITS*/; i++)
by
for (i = 0; i < z/*NUMDIGITS*/; i++)
Then we just print out the digits
for( i = d -1; i >= 0; i--)
cout << (int)a[i];
cout<<"\n";
and free the allocated memory
delete []a;