【问题标题】:greatest divisor of a number and prime factors relation一个数的最大除数和质因数的关系
【发布时间】:2020-09-04 03:13:08
【问题描述】:

问题如下: 给定两个数 n 和 k。对于区间 [1, n] 中的每个数字,您的任务是计算其不能被 k 整除的最大除数。打印所有这些除数的总和。 注意:k 总是一个素数。 t=3*10^5,1

我对这个问题的看法: 对于 1 到 n 范围内的每个 i,所需的除数是 i 本身,仅当 i 不是 k 的倍数时。 如果 i 是 k 的倍数,那么我们必须找到一个数的最大除数并与 k 匹配。如果不匹配,那么这个除数就是我的答案。否则,第二大除数就是我的答案。

例如,取 n=10 和 k=2,1 到 10 范围内的每个 i 所需的除数为 1, 1, 3, 1, 5, 3, 7, 1, 9, 5。这些除数的和是 36。所以 ans=36。

我的代码适用于一些测试用例,但在一些测试用例中失败了。

#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';
 }

 }

在我做错的地方有人可以帮助我,或者建议我一些更快的逻辑来做这个问题,因为我的一些测试用例显示 TIME LIMIT EXCEED

查看所有可能的解释后,我将代码修改如下:

#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';

}

}

但它仍然为 3 个测试用例提供 TIME LIMIT EXCEED。有人请帮忙。

【问题讨论】:

  • 请附上minimal reproducible example。对于我们看不到的代码,我们无能为力
  • 您的问题陈述有点可疑。 “注意:k 始终是素数。”k 是什么?该注释是您在文本中提及它的唯一地方
  • @idclev463035818 对不起,先生,只是输入错误。
  • 出于好奇:您在哪个竞赛网站找到了挑战?
  • 再提示一个:以 n=200, k=7 为例,使用暴力破解程序。您可能会在那里看到一个模式(数字可以被 7、49 整除,...)。然后你需要像 Gauss 那样对从 1 到 100 的数字总和进行的创造性思维。结合所有这些应该引导你走上解决方案的道路。

标签: c++ algorithm math factors sieve-of-eratosthenes


【解决方案1】:

这本身就是一个数学问题: 如果 cur = [1..n],正如您已经注意到的,最大除数 = dmax = cur 是,如果 cur % k != 0,否则 dmax 必须

所以这应该看起来像这样(不保证只是输入 - 也许我错过了一些想法):

#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;
        }
    }
}

【讨论】:

  • 方法是正确的。如果cur 可以被k 整除,那么cur 的质因数至少包含一个k,并且您必须消除所有这些质因数才能得到一个不再能被k 整除的除数。但是在测试十亿个数字时,这种方法可能仍然很慢。
  • 这当然是正确的,但我或多或少优雅地从责任中偷走了自己的话:这当然也更优雅地可能(因为由于素数分解,dmax 必须再次成为素数)."。
  • 完全没问题,将一些工作留给 OP 进行竞赛挑战。也许我们可以在下周回来看看他的进步,如果需要,改进答案。
  • @RalfKleberhoff 它为所有测试用例提供了超过时间限制。看起来很难在规定时间内通过所有测试用例。
  • 看看@OneLyner 的回答。他有关键提示可以找到快速解决方案,而无需遍历所有低于 n 的数字 pp。但是你仍然需要弄清楚细节 - 这是这些挑战中有趣的部分,我不想从你那里拿走。
【解决方案2】:

就像其他人已经说过的那样,看看约束:t=3*10^5,1&lt;=n&lt;=10^9, 2&lt;=k&lt;=10^9

如果您的测试具有复杂性O(n)(通过循环计算总和),您最终将执行t * n ~ 10^14。太多了。

这个挑战是数学挑战。您需要使用两个事实:

  • 如您所见,如果i = j * k^sj%k != 0,最大除数为j
  • sum_{i=1}^t i = (t * (t+1)) / 2

我们开始

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

那么对于k * x 形式的所有数字,我们添加了太多,让我们更正一下:

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

继续输入k^2 * x ...然后k^p * x,直到总和为空...

好的,人们开始写代码了,下面是一个 Python 小函数:

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

在这里https://repl.it/repls/OlivedrabKeyProjections

【讨论】:

  • 这里的 j,s 是什么??
  • ,你能举个例子详细说明一下你的解释吗?
  • 先生,请回复, sum=(n*(n+1))/2 仅在数字从 1 到 n 时使用。但这里的数字可能是不规则的。
  • 从完整的总和开始,然后尝试找到您需要删除以更正它的值。
  • 先生,在 start 使用 sum as (n*(n+1))/2 后,10 个测试用例中有 7 个通过。仍有 3 个测试用例抛出 TIME LIMIT EXCEED。
【解决方案3】:

我想知道这样的事情是不是 One Lyner 的意思。

(注意,这段代码有两个错误,在cmets中有描述,也可以通过One Lyner的新代码来说明。)

C++ 代码:

#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';
    }
}

【讨论】:

  • 先生,请看我上面修改过的代码(第二个)。它为 3 个测试用例提供 TLE。如何在我的代码中删除该 while 循环?
  • 我对 javascipt 了解不多。所以很难理解你的代码。
  • @sushan 小 k,看来你代码中的 while 循环仍然可以是 O(n)。我将我的代码转换为 C++。
  • 先生,您的代码输入错误答案。取 t=1,n=1000000000 和 k=97。答案应该是 494897959532893312 但您的代码给出的是 494844813310384672
  • @sushan 你从哪里得到 n=1000000000 和 k=97、494897959532893312 的结果?
猜你喜欢
  • 1970-01-01
  • 2019-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-13
  • 2013-07-06
相关资源
最近更新 更多