How to calculate number of partitions of n? - algorithm

How can I calculate number of partitions of n mod 1e9+7, where n<=50000.
See http://oeis.org/A000041 .
Here is the source problem http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1259 (In Chinese)
Simply applying the formula: a(n) = (1/n) * Sum_{k=0..n-1} d(n-k)*a(k) gave me an O(n^2) solution.
typedef long long ll;
ll MOD=1e9+7;
ll qp(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1) ans=ans*a%MOD;
a=a*a%MOD;
b>>=1;
}
return ans;
}
ll a[50003],d[50003];
#define S 1000
int main()
{
for(int i=1; i<=S; i++)
{
for(int j=1; j<=S; j++)
{
if(i%j==0) d[i]+=j;
}
d[i]%=MOD;
}
a[0]=1;
for(int i=1; i<=S; i++)
{
ll qwq=0;
for(int j=0; j<i; j++) qwq=qwq+d[i-j]*a[j]%MOD;
qwq%=MOD;
a[i]=qwq*qp(i,MOD-2)%MOD;
}
int n;
cin>>n;
cout<<a[n]<<"\n";
}

I would solve it with a different approach.
Dynamic Programming:
DP[N,K] = number of partitions of N using only numbers 1..K
DP[0,k] = 1
DP[n,0] = 0
DP[n,k] when n<0 = 0
DP[n,k] when n>0 = DP[n-k,k] + DP[n,k-1]
Recursive implementation using memoization:
ll partition(ll n, ll max){
if (max == 0)
return 0;
if (n == 0)
return 1;
if (n < 0)
return 0;
if (memo[n][max] != 0)
return memo[n][max];
else
return (memo[n][max] = (partition(n, max-1) + partition(n-max,max)));
}
Live-Example

Related

Having some trouble with solving for runtime

In Big-Θ notation, analyze the running time of the following three pieces of code/pseudo-code, describing it as a function of the input, n.
1.
void f1(int n)
{
int t = sqrt(n);
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
// do something O(1)
}
n -= t;
}
}
2.
Assume A is an array of size n+1.
void f2(int* A, int n)
{
for(int i=1; i <= n; i++){
for(int k=1; k <= n; k++){
if( A[k] == i){
for(int m=1; m <= n; m=m+m){
// do something that takes O(1) time
// Assume the contents of the A[] array are not changed
}
}
}
}
}
3.
void f3(int* A, int n)
{
if(n <= 1) return;
else {
f3(A, n-2);
// do something that takes O(1) time
f3(A, n-2);
}
}
Any help would be appreciated.

Maximal Square with 0 inside

The question Maximal Square in https://leetcode.com/problems/maximal-square/description/ is easy to solve by DP. But how to solve the following up question:
Similar as Maximal Square question, but allows 0's inside a square, "inside" means the border of the square must be all 1.
For example, given the following matrix:
1 0 1 0 0
1 0 1 1 1
1 1 1 0 1
1 0 1 1 1
Return 9.
Update: Because the 3*3 matrix in the right bottom corner matches the requirement, the border must be all 1, and there can be 0 inside the square.
I thought up a O(n^3) algorithm: take maze[i][j] as the right bottom corner of the square if maze[i][j] == 1, enumerate the edge length of the square. If edge length is 3, consider whether maze[i - 2][j - 2], maze[i][j - 2], maze[i - 2][j], maze[i][j] forms a square with the numbers in each edge are all 1.
Is there any better algorithm?
Your problem can be solved in O (n * m) time and space complexity, where n is total rows and m is total columns in matrix. You may look at the code below where I have commented out to make it understandable.
Please, let me know if you have any doubt.
#include <bits/stdc++.h>
using namespace std;
void precalRowSum(vector< vector<int> >& grid, vector< vector<int> >&rowSum, int n, int m) {
// contiguous sum upto jth position in ith row
for (int i = 0; i < n; ++i) {
int sum = 0;
for (int j = 0; j < m; ++j) {
if (grid[i][j] == 1) {
sum++;
} else {
sum = 0;
}
rowSum[i][j] = sum;
}
}
}
void precalColSum(vector< vector<int> >& grid, vector< vector<int> >&colSum, int n, int m) {
// contiguous sum upto ith position in jth column
for (int j = 0; j < m; ++j) {
int sum = 0;
for (int i = 0; i < n; ++i) {
if (grid[i][j] == 1) {
sum++;
} else {
sum = 0;
}
colSum[i][j] = sum;
}
}
}
int solve(vector< vector<int> >& grid, int n, int m) {
vector< vector<int> >rowSum(n, vector<int>(m, 0));
vector< vector<int> >colSum(n, vector<int>(m, 0));
// calculate rowwise sum for 1
precalRowSum(grid, rowSum, n, m);
// calculate colwise sum for 1
precalColSum(grid, colSum, n, m);
vector< vector<int> >zerosHeight(n, vector<int>(m, 0));
int ans = 0;
for (int i = 0; i < (n - 1); ++i) {
for (int j = 0; j < m; ++j) {
zerosHeight[i][j] = ( grid[i][j] == 0 );
if (grid[i][j] == 0 && i > 0) {
zerosHeight[i][j] += zerosHeight[i - 1][j];
}
}
if (i == 0) continue;
// perform calculation on ith row
for (int j = 1; j < m; ) {
int height = zerosHeight[i][j];
if (!height) {
j++;
continue;
}
int cnt = 0;
while (j < m && height == zerosHeight[i][j]) {
j++;
cnt++;
}
if ( j == m) break;
if (cnt == height && (i - cnt) >= 0 ) {
// zeros are valid, now check validity for boundries
// Check validity of upper boundray, lower boundary, left boundary, right boundary respectively
if (rowSum[i - cnt][j] >= (cnt + 2) && rowSum[i + 1][j] >= (cnt + 2) &&
colSum[i + 1][j - cnt - 1] >= (cnt + 2) && colSum[i + 1][j] >= (cnt + 2) ){
ans = max(ans, (cnt + 2) * (cnt + 2) );
}
}
}
}
return ans;
}
int main() {
int n, m;
cin>>n>>m;
vector< vector<int> >grid;
for (int i = 0; i < n; ++i) {
vector<int>tmp;
for (int j = 0; j < m; ++j) {
int x;
cin>>x;
tmp.push_back(x);
}
grid.push_back(tmp);
}
cout<<endl;
cout<< solve(grid, n, m) <<endl;
return 0;
}

Number of heaps using n distinct integers- Time complexity

I am solving the problem to find the maximum number of max heaps that can be formed using n distinct integers (say 1..n). I have solved it using the following
recurrence with some help from this: https://www.quora.com/How-many-Binary-heaps-can-be-made-from-N-distinct-elements :
T(N) = N-1 (C) L * T(L) * T(R). where L is the number of nodes in the left subtree and R is the number of nodes in the right subtree. I have also implemented it in c++ using dynamic programming. But I am stuck in find the time complexity of it. Can someone help me with this?
#include <iostream>
using namespace std;
#define MAXN 105 //maximum value of n here
int dp[MAXN]; //dp[i] = number of max heaps for i distinct integers
int nck[MAXN][MAXN]; //nck[i][j] = number of ways to choose j elements form i elements, no order */
int log2[MAXN]; //log2[i] = floor of logarithm of base 2 of i
//to calculate nCk
int choose(int n, int k)
{
if (k > n)
return 0;
if (n <= 1)
return 1;
if (k == 0)
return 1;
if (nck[n][k] != -1)
return nck[n][k];
int answer = choose(n-1, k-1) + choose(n-1, k);
nck[n][k] = answer;
return answer;
}
//calculate l for give value of n
int getLeft(int n)
{
if (n == 1)
return 0;
int h = log2[n];
//max number of elements that can be present in the hth level of any heap
int numh = (1 << h); //(2 ^ h)
//number of elements that are actually present in last level(hth level)
//(2^h - 1)
int last = n - ((1 << h) - 1);
//if more than half-filled
if (last >= (numh / 2))
return (1 << h) - 1; // (2^h) - 1
else
return (1 << h) - 1 - ((numh / 2) - last);
}
//find maximum number of heaps for n
int numberOfHeaps(int n)
{
if (n <= 1)
return 1;
if (dp[n] != -1)
return dp[n];
int left = getLeft(n);
int ans = (choose(n-1, left) * numberOfHeaps(left)) * (numberOfHeaps(n-1-left));
dp[n] = ans;
return ans;
}
//function to intialize arrays
int solve(int n)
{
for (int i = 0; i <= n; i++)
dp[i] = -1;
for (int i = 0; i <= n; i++)
for (int j = 0; j <=n; j++)
nck[i][j] = -1;
int currLog2 = -1;
int currPower2 = 1;
//for each power of two find logarithm
for (int i = 1; i <= n; i++)
{
if (currPower2 == i)
{
currLog2++;
currPower2 *= 2;
}
log2[i] = currLog2;
}
return numberOfHeaps(n);
}
//driver function
int main()
{
int n=10;
cout << solve(n) << endl;
return 0;
}

Algorithm. How to find longest subsequence of integers in an array such that gcd of any two consecutive number in the sequence is greather than 1?

Given`en an array of integers. We have to find the length of the longest subsequence of integers such that gcd of any two consecutive elements in the sequence is greater than 1.
for ex: if array = [12, 8, 2, 3, 6, 9]
then one such subsequence can be = {12, 8, 2, 6, 9}
other one can be= {12, 3, 6, 9}
I tried to solve this problem by dynamic programming. Assume that maxCount is the array such that maxCount[i] will have the length of such longest subsequence
ending at index i.
`maxCount[0]=1 ;
for(i=1; i<N; i++)
{
max = 1 ;
for(j=i-1; j>=0; j--)
{
if(gcd(arr[i], arr[j]) > 1)
{
temp = maxCount[j] + 1 ;
if(temp > max)
max = temp ;
}
}
maxCount[i]=max;
}``
max = 0;
for(i=0; i<N; i++)
{
if(maxCount[i] > max)
max = maxCount[i] ;
}
cout<<max<<endl ;
`
But, this approach is getting timeout. As its time complexity is O(N^2). Can we improve the time complexity?
The condition "gcd is greater than 1" means that numbers have at least one common divisor. So, let dp[i] equals to the length of longest sequence finishing on a number divisible by i.
int n;
cin >> n;
const int MAX_NUM = 100 * 1000;
static int dp[MAX_NUM];
for(int i = 0; i < n; ++i)
{
int x;
cin >> x;
int cur = 1;
vector<int> d;
for(int i = 2; i * i <= x; ++i)
{
if(x % i == 0)
{
cur = max(cur, dp[i] + 1);
cur = max(cur, dp[x / i] + 1);
d.push_back(i);
d.push_back(x / i);
}
}
if(x > 1)
{
cur = max(cur, dp[x] + 1);
d.push_back(x);
}
for(int j : d)
{
dp[j] = cur;
}
}
cout << *max_element(dp, dp + MAX_NUM) << endl;
This solution has O(N * sqrt(MAX_NUM)) complexity. Actually you can calculate dp values only for prime numbers. To implement this you should be able to get prime factorization in less than O(N^0.5) time (this method, for example). That optimization should cast complexity to O(N * factorization + Nlog(N)). As memory optimization, you can replace dp array with map or unordered_map.
GCD takes log m time, where m is the maximum number in the array. Therefore, using a Segment Tree and binary search, one can reduce the time complexity to O(n log (m² * n)) (with O(n log m) preprocessing). This list details other data structures that can be used for RMQ-type queries and to reduce the complexity further.
Here is one possible implementation of this:
#include <bits/stdc++.h>
using namespace std;
struct SegTree {
using ftype = function<int(int, int)>;
vector<int> vec;
int l, og, dummy;
ftype f;
template<typename T> SegTree(const vector<T> &v, const T &x, const ftype &func) : og(v.size()), f(func), l(1), dummy(x) {
assert(og >= 1);
while (l < og) l *= 2;
vec = vector<int>(l*2);
for (int i = l; i < l+og; i++) vec[i] = v[i-l];
for (int i = l+og; i < 2*l; i++) vec[i] = dummy;
for (int i = l-1; i >= 1; i--) {
if (vec[2*i] == dummy && vec[2*i+1] == dummy) vec[i] = dummy;
else if (vec[2*i] == dummy) vec[i] = vec[2*i+1];
else if (vec[2*i+1] == dummy) vec[i] = vec[2*i];
else vec[i] = f(vec[2*i], vec[2*i+1]);
}
}
SegTree() {}
void valid(int x) {assert(x >= 0 && x < og);}
int get(int a, int b) {
valid(a); valid(b); assert(b >= a);
a += l; b += l;
int s = vec[a];
a++;
while (a <= b) {
if (a % 2 == 1) {
if (vec[a] != dummy) s = f(s, vec[a]);
a++;
}
if (b % 2 == 0) {
if (vec[b] != dummy) s = f(s, vec[b]);
b--;
}
a /= 2; b /= 2;
}
return s;
}
void add(int x, int c) {
valid(x);
x += l;
vec[x] += c;
for (x /= 2; x >= 1; x /= 2) {
if (vec[2*x] == dummy && vec[2*x+1] == dummy) vec[x] = dummy;
else if (vec[2*x] == dummy) vec[x] = vec[2*x+1];
else if (vec[2*x+1] == dummy) vec[x] = vec[2*x];
else vec[x] = f(vec[2*x], vec[2*x+1]);
}
}
void update(int x, int c) {add(x, c-vec[x+l]);}
};
// Constructor (where val is something that an element in the array is
// guaranteed to never reach):
// SegTree st(vec, val, func);
// finds longest subsequence where GCD is greater than 1
int longest(const vector<int> &vec) {
int l = vec.size();
SegTree st(vec, -1, [](int a, int b){return __gcd(a, b);});
// checks if a certain length is valid in O(n log (m² * n)) time
auto valid = [&](int n) -> bool {
for (int i = 0; i <= l-n; i++) {
if (st.get(i, i+n-1) != 1) {
return true;
}
}
return false;
};
int length = 0;
// do a "binary search" on the best possible length
for (int i = l; i >= 1; i /= 2) {
while (length+i <= l && valid(length+i)) {
length += i;
}
}
return length;
}

Count null diagonals in a matrix

I'm trying to create a program that counts the number of null diagonals in a square matrix, but I can't seem to find the correct way of making my index run correctly through the matrix. Here's the incorrect code I've got so far:
# include<stdio.h>
# define MAX 100
int DiagonNull (int n, int A[MAX][MAX]) {
int i, j, count, null;
banda = 0;
for(i = n - 1; i >= 0; i--){
count = 0;
for(j = 0; j <= n && j < i - 1; j++){
if (A[i][j] == 0)
count++;
}
if (count == n - i) /* n - i = number of elements in diagonal */
null++;
else
i = - 1;
}
return null;
}
int main () {
int n, A[MAX][MAX], i, j, null;
printf ("Enter value of n to create a square matrix A of order n: ");
scanf ("%d", &n);
printf ("Enter the elements of matrix A: ");
for (i = 0; i < n; i++){
for (j = 0; j < n; j++){
scanf("%d", &A[i][j]);
}
}
null = DiagonNull (n, A);
printf ("Matrix has null %d diagonals", null);
return 0;
}

Resources