Update
Going with the binary search approach, here is my new code:
// compute X/ai sum
long long summarize(long long ar[], long long n, long long X)
{
long long sum = 0;
for (long long i = 0; i < n; i++)
{
sum += X/ar[i];
}
return sum;
}
bool get_range(long long ar[], int n, int m, pair<long long, long long>& range)
{
long long sum = 0;
long long x;
// reduce range
while (range.first < range.second)
{
x = (range.first + range.second) / 2;
sum = summarize(ar, n, x);
if (sum < m)
{
range.first = x + 1;
}
else if (sum > m)
{
range.second = x;
}
else if (x == range.first)
{
return true; // single element
}
else
{
break;
}
}
if (sum != m)
{
return false;
}
// check surroundings for lower / upper bound.
sum = summarize(ar, n, range.first);
if (sum != m)
{
auto r1 = make_pair(range.first + 1, x);
if (get_range(ar, n, m, r1))
{
range.first = r1.first;
}
else
{
range.first = x;
}
}
sum = summarize(ar, n, range.second - 1);
if (sum != m)
{
auto r2 = make_pair(x + 1, range.second - 1);
if (get_range(ar, n, m, r2))
{
range.second = r2.second;
}
else
{
range.second = x + 1;
}
}
return true;
}
int main()
{
int n, m;
cin >> n >> m;
long long *ar = new long long[n];
long long ar_min = LLONG_MAX;
for(long long i = 0; i < n; i++)
{
cin >> ar[i];
ar_min = min(ar[i], ar_min);
}
// initial range of possible X values
auto range = make_pair(m / (ar_min * n), m * ar_min);
if (get_range(ar, n, m, range))
{
cout << (range.second - range.first) << endl;
}
else
{
cout << 0 << endl;
}
}
Core functionality is the get_range function, which takes a possible range ([range.first, range.second), so second is not part of the range) and reduces the range so all elements in range satisfy the condition. It is first iteratively adjusting range bounds until the middle of the range is part of the result or until it's clear that there is no result in range. Then, if there is any result, it is recursively checking the sub-ranges below and above the found result in order to retrieve the bounds of the whole result range.
Version 1
You are only dealing with positive numbers greater than zero.
M = floor(X/a1) + floor(X/a2) + ... + floor(X/an)
For every sub-term floor(X/a1), there is floor(X1/ai) <= floor(X2/ai) if X1 < X2. So the only possible X values resulting in M are those, where floor(X1/ai) == floor(X2/ai) for all i (or all ai).
For each ai this is exactly the Range of X1=k*ai until X2=k*ai+(ai-1) for some k.
This means, if any solution exists, the range of X values will be between k*min(ai) and (k+1)*min(ai) for some 0 < k <= m.
So it might be worth to first get the range of possible results and then check the individual values only within the range.
Resulting algorithm:
// compute X/ai sum
long long summarize(long long ar[], long long n, long long X)
{
long long sum = 0;
for (long long i = 0; i < n; i++)
{
sum += X/ar[i];
}
return sum;
}
int main()
{
int n, m;
cin >> n >> m;
long long *ar = new long long[n];
long long ar_min = LLONG_MAX;
for(long long i = 0; i < n; i++)
{
cin >> ar[i];
ar_min = min(ar[i], ar_min);
}
// lowest possible k
long long k = m / (ar_min * n);
// get the value k for a possible range of X values
for (; k <= m; k++)
{
auto x = ar_min * (k + 1);
long long sum = summarize(ar, n, x);
if (sum > m)
{
break;
}
}
long long X_min = k * ar_min, X_max = (k + 1) * ar_min;
long long result = 0;
// count possible X values
for (long long x = X_min; x < X_max; x++)
{
long long sum = summarize(ar, n, x);
if (sum == m)
{
++result;
}
else if (sum > m)
{
break;
}
}
cout << result << endl;
}
It got a bit more complicated than I first expected. I hope it's still some sort of improvement.
N= 3 andM= 10. And we gota1= 1,a2= 1, anda3= 1. We got no possibilities ofX.