spoj NAJPWG的解决方案。给TLE

时间:2015-06-08 21:06:26

标签: c algorithm greatest-common-divisor

问题的链接是 - spoj question

我试过通过这种方法解决问题 - N范围内的对数= N-1范围内的对数+一些新对。

但我不知道还应该在这里做什么优化来避免TLE。我也读过有关euler totient函数的内容,但我不能真正理解这种方法。我猜我已经阅读了4种计算euler phi的方法,但都需要相同的O(n ^ 2)。

P.S - 我想知道关于进一步的方法应该是什么,而不是直接的解决方案。提示会做。 非常感谢提前。

我对这个问题的代码是 -

#include<stdio.h>
typedef unsigned long long int ull;
ull a[100000] = {0};

inline ull g()
{
    ull n=0;
    char ch;
    ch = getchar_unlocked();
    while(ch < '0' || ch > '9')
        ch = getchar_unlocked();
    while(ch >= '0' && ch <= '9') {
        n = (n<<3) + (n<<1) + (ch - '0');
        ch = getchar_unlocked();
    }
    return n;
}

ull gcd( ull a , ull b)
{
    if(b == 0)
        return a;
    else 
        return gcd(b , a % b);
}

ull find(ull n)
{
    if(n == 0 || n == 1)
        return n;
    else if(a[n] != 0)
        return n;
    else
        return find(n-1);
}

ull range(ull n)
{
    ull c, i, nf,t;
    nf = find(n);
    c = a[nf];
    t = nf;
    nf++;
    while(nf <= n) {
        a[nf] = a[t];
        for(i = 2 ; i <= nf ; i++) {
            ull gd = gcd(i,nf);
            if(gd > 1) {
                c++;
                a[nf]++;
            }
        }
        nf++;
    }
    return c;
}

int main()
{
    ull t = g();
    ull i = 1;
    while(t--) {
        ull n = g();
        if(a[n] == 0)
            a[n] = range(n);
        printf("Case %llu: %llu\n",i++,a[n]);
    }   
    return 0;
}

2 个答案:

答案 0 :(得分:0)

只是去尝试并获得AC。 enter image description here

正如你所说的那样,这里有一些基于我的AC解决方案和你的尝试:

  1. Phi功能是bonus?真?至少在我的代码中,我不认为它是O(n^2)
  2. O(n^2)功能不需要
  3. 这是一个简单的数学/数论问题,而不是DP问题
  4. 预计算,预计算,预计算!你可以预先计算很多东西,比如每个输入GCD的循环,你可以在n输出答案!
  5. Learn Prime Sieve&amp;在你研究Phi函数之前首先算术的基本定理。 (或者你可以记住Phi函数的公式,它确实很容易记住)

答案 1 :(得分:0)

嗯,我认为一个更好的方法是根据Euler的Totient函数来考虑...... Totient函数给出了数字n以下的数字的数量,即与它共同的,即GCD(n,x)= 1其中

x&lt; n。

现在直到n的对是对,直到n-1 +对为n,即(n的n-幂函数)。

对于Totient函数,请参阅Link

我认为你需要在Totient Sieve的帮助下预处理每个数字的总数直到10 ^ 6,因为N * Root(N)不会及时通过。