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 <= 10
7
1 <= k <= 10
5
1 <= r
i
<= 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.
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)
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.
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 .
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With