user13499843
user13499843

Reputation:

greatest divisor of a number and prime factors relation

Question is as follows : Given two numbers n and k. For each number in the interval [1, n], your task is to calculate its largest divisor that is not divisible by k. Print the sum of all these divisors. Note: k is always a prime number. t=3*10^5,1<=n<=10^9, 2<=k<=10^9

My approach toward the question: for every i in range 1 to n, the required divisors is i itself,only when that i is not a multiple of k. If that i is multiple of k, then we have to find the greatest divisor of a number and match with k. If it does not match, then this divisor is my answer. otherwise, 2nd largest divisor is my answer.

for example,take n=10 and k=2, required divisors for every i in range 1 to 10 is 1, 1, 3, 1, 5, 3, 7, 1, 9, 5. sum of these divisors are 36. So ans=36.

My code,which works for a few test cases and failed for some.

#include<bits/stdc++.h>
using namespace std;
#define ll long long int

ll div2(ll n, ll k) {
if (n % k != 0 || n == 1) {
    return n;
}

else {
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) {
            ll aa = n / i;
            if (aa % k != 0) {
                return aa;
            }
        }
    }
}
return 1;
}



int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t;
cin >> t;

while (t--) {
    ll n, k;
    cin >> n >> k;
    ll sum = 0, pp;

    for (pp = 1; pp <= n; pp++) {
        //cout << div2(pp, k);
        sum = sum + div2(pp, k);
    }
    cout << sum << '\n';
 }

 }

Can someone help me where I am doing wrong or suggest me some faster logic to do this question as some of my test cases is showing TIME LIMIT EXCEED

after looking every possible explanation , i modify my code as follows:

#include<bits/stdc++.h>
using namespace std;
#define ll long long int

int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t;
cin >> t;

while (t--) {
    ll n, i;
    ll k, sum;
    cin >> n >> k;

    sum = (n * (n + 1)) / 2;

    for (i = k; i <= n; i = i + k) {
        ll dmax = i / k;

        while (dmax % k == 0) {
            dmax = dmax / k;
        }
        sum = (sum - i) + dmax;

    }
    cout << sum << '\n';

}

}

But still it is giving TIME LIMIT EXCEED for 3 test cases. Someone please help.

Upvotes: 5

Views: 1927

Answers (3)

גלעד ברקן
גלעד ברקן

Reputation: 23955

I wonder if something like this is what One Lyner means.

(Note, this code has two errors in it, which are described in the comments, as well as can be elucidated by One Lyner's new code.)

C++ code:

#include <vector>
#include <iostream>
using namespace std;
#define ll long long int

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int t;
    cin >> t;

    while (t--) {
        ll n;
        ll k, _k, result;
        vector<ll> powers;
        cin >> n >> k;

        result = n * (n + 1) / 2;
        _k = k;

        while (_k <= n) {
            powers.push_back(_k);
            _k = _k * k;
        }

        for (ll p : powers) {
            ll num_js = n / p;
            result -= num_js * (num_js + 1) / 2 * (p - 1);
            int i = 0;
            while (p * powers[i] <= n) {
                result += powers[i] * (p - 1);
                i = i + 1;
            }
        }

        cout << result << '\n';
    }
}

Upvotes: 0

One Lyner
One Lyner

Reputation: 2004

Like others already said, look at the constraints: t=3*10^5,1<=n<=10^9, 2<=k<=10^9.

If your test has a complexity O(n), which computing the sum via a loop has, you'll end up doing a t * n ~ 10^14. That's too much.

This challenge is a math one. You'll need to use two facts:

  • as you already saw, if i = j * k^s with j%k != 0, the largest divisor is j;
  • sum_{i=1}^t i = (t * (t+1)) / 2

We start with

S = sum(range(1, n)) = n * (n+1) / 2

then for all number of the form k * x we added too much, let's correct:

S = S - sum(k*x for x in range(1, n/k)) + sum(x for x in range(1, n/k))
  = S - (k - 1) * (n/k) * (n/k + 1) / 2

continue for number of the form k^2 * x ... then k^p * x until the sum is empty...

Ok, people start writing code, so here's a small Python function:

def so61867604(n, k):
    S = (n * (n+1)) // 2
    k_pow = k
    while k_pow <= n:
        up = n // k_pow
        S = S - (k - 1) * (up * (up + 1)) // 2
        k_pow *= k
    return S

and in action here https://repl.it/repls/OlivedrabKeyProjections

Upvotes: 3

Wolfgang
Wolfgang

Reputation: 340

In itself this is more of a mathematical problem: If cur = [1..n], as you have already noticed, the largest divisor = dmax = cur is, if cur % k != 0, otherwise dmax must be < cur. From k we know that it is at most divisible into other prime numbers... Since we want to make sure that dmax is not divisible by k we can do this with a while loop... whereby this is certainly also more elegantly possible (since dmax must be a prime number again due to the prime factorization).

So this should look like this (without guarantee just typed down - maybe I missed something in my thinking):

#include <iostream>

int main() {
    unsigned long long n = 10;
    unsigned long long k = 2;

    for (auto cur_n = decltype(n){1}; cur_n <= n; cur_n++)
    {
        if (cur_n % k != 0) {
            std::cout << "Largest divisor for " << cur_n << ": " << cur_n << " (SELF)" << std::endl;
        } else {
            unsigned long long dmax= cur_n/k;

            while (dmax%k == 0)
                dmax= dmax/k;
            std::cout << "Largest divisor for " << cur_n << ": " << dmax<< std::endl;
        }
    }
}

Upvotes: 2

Related Questions