Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Number of ways to write n as sum of k numbers with restrictions on each part

Title says it all.

I need to split n as sum of k parts where each part ki should be in the range of 1 <= ki <= ri for given array r.

for example -

n = 4, k = 3 and r = [2, 2, 1]
ans = 2
#[2, 1, 1], [1, 2, 1]

Order matters. (2, 1, 1) and (1, 2, 1) are different.

I taught of solving it using stars and bars method, but be because of upper bound ri i dont know to to approach it.

i implemented a direct recursion function and it works fine for small values only.

Constraints of original problem are

1 <= n <= 107

1 <= k <= 105

1 <= ri<= 51

All calculations will be done under prime Modulo.

i found a similar problem here but i don't know how to implement in program. HERE

My brute-force recursive function -

#define MAX 1000
const int md = 1e9 + 7;

vector <int> k;
vector <map<int, int>> mapper;

vector <int> hold;

int solve(int sum, int cur){

    if(cur == (k.size() - 1) &&  sum >= 1 && sum <= k[cur]) return 1;
    if(cur == (k.size() - 1) &&  (sum < 1 || sum > k[cur])) return 0;

    if(mapper[cur].find(sum) != mapper[cur].end())
        return mapper[cur][sum];

    int ans = 0;
    int start = 1;

    for(int i=start; i<=k[cur]; ++i){


        int remain = sum - i;
        int seg = (k.size() - cur) - 1;
        if(remain < seg) break;

        int res = solve(sum - i, cur + 1);
        ans = (1LL * ans + res) % md;
    }

    mapper[cur][sum] = ans;
    return ans;
}


int main(){

    for(int i=0; i<MAX; ++i) k.push_back(51);  // restriction for each part default 51
    mapper.resize(MAX);

    cout << solve(MAX + MAX, 0) << endl;
}

Instead of using a map for storing result of computation i used a two dimensional array and it gave very good performance boost but i cannot use it because of large n and k values.

How could i improve my recursive function or what are other ways of solving this problem.

like image 813
Atul Avatar asked Dec 22 '17 03:12

Atul


People also ask

How many ways can 2 be split into k non-negative integers?

Input: N = 2, K = 3 Output: 6 Explanation: The total ways in which 2 can be split into K non-negative integers are: 1. (0, 0, 2) 2. (0, 2, 0) 3. (2, 0, 0) 4. (0, 1, 1) 5. (1, 0, 1) 6. (1, 1, 0)

How many ways can N be written as a sum of integers?

Given a positive integer N, the task is to find the number of different ways in which N can be written as a sum of two or more positive integers. Input: N = 5 Output: 6 Explanation: 1+1+1+1+1 1+1+1+2 1+1+3 1+4 2+1+2 2+3 So, a total of 6 ways.

How to choose K-1 objects out of n-1?

So, in general, for N there will be N-1 spaces between all 1, and out of those choose k-1 and place a comma in between those 1. In between the rest 1’s, place ‘+’ signs. So the way of choosing K-1 objects out of N-1 is . The dynamic programming approach is used to calculate .

What is the approach to the problem of sum of integers?

The approach to the problem is to observe a sequence and use combinations to solve the problem. To obtain a number N, N 1’s are required, summation of N 1’s will give N. The problem allows you to use K integers only to make N.


1 Answers

That's interesting problem.

First lets say r_i = r_i - 1, n = n - k, numbers in [0, r_i] just for convenience. Now it's possible to add some fictitious numbers to make m the power of 2 without changing answer.

Now let's represent each interval of [0, r_i] as polynomial 1 * x ^ 0 + 1 * x ^ 1 + ... + 1 * x & r_i. Now if we multiply all these polynomials, coefficient at x ^ n will be answer.

Here is structure called Number Theoretic Transform (NTT) which allows to multiply two polynomials modulo p in O(size * log(size)).

If you will just multiply it using NTT, code will work in something like O(n * k * log (k * max(r))). It's very slow.

But now our fictive numbers help. Let's use divide and conquer technics. We'll make O(log m) steps, on each step multiply 2 * i-th and 2 * i + 1-th polynomials. In the next step we'll multiply resulting polynomials of this step.

Each step works in O(k * log(k)) and there is O(log(k)) steps, so algorhitm works in O(k * log^2 (k)). It's fast asymptotically, but I'm not sure if it fits TL for this problem. I think it will work about 20 seconds on max test.

like image 199
Livace Avatar answered Oct 12 '22 12:10

Livace