【问题标题】:Euler's totient function practice code fails in online judge欧拉全功能练习代码在线判断失败
【发布时间】:2018-03-02 08:31:45
【问题描述】:

这是专门UVA problem number 11327

给定一系列介于 0 和 1 之间的所有有理数(0/1、1/1、1/2、1/3、2/3、...、n/d),打印第 k 个分数

我使用了他们的调试器,我的程序输出的答案与他们给出的完全相同,但法官仍将其标记为不正确。

我正在使用Euler's totient function 来查找分母并遍历等于 1 的 GCD 来查找分子。据我在网上找到的,这应该足够了。

任何帮助将不胜感激。

#include <iostream>
#include <stdlib.h>
#include <vector>
#include <math.h>
using namespace std;

//Calculate the greatest common divisor of a and b
long long GCD(long long a, long long b){
    if (a == 0){
        return b;
    }
    return GCD(b%a, a);
}

int main(){
    long long input;
    vector <long long> inputVector;
    vector <long long> phiValues;
    long long totient;
    long long total;
    int numerator;
    int denominator;

    while(cin >> input){
        if(input == 0){
            break;
        }
        inputVector.push_back(input);
    }

    // Calculate phi for all integers from 1 to
    // 20000 and store them 
    for(int i = 1; i <= 200000; i++){
        long long current = i;
        totient = current;
        for(long long k = 2; k <= sqrt(i); k++){
            if(current % k == 0){
                totient -= totient / k;
                while(current % k == 0){
                    current /= k;
                }
            }
        }
        if(current > 1){
            totient -= totient / current;
        }
        phiValues.push_back(totient);
    }

    for(int i = 0; i < inputVector.size(); i++){
        long long N = inputVector[i];
        total = 1;
        for(int j = 0; j <= phiValues.size(); j++){
            if(total >= N){
                if(N == 1){ //For the case of N = 1
                    denominator = 1;
                }else{ 
                    denominator = j; 
                }
                total -= phiValues[j-1]; 
                break;
            }
            total += phiValues[j];

        }
        int index = 0;
        for(int j = 1; j <= denominator; j++){
            if(GCD(j, denominator) == 1){
                index++;
                if(index == N - total){
                    numerator = j;
                    break;
                }
            }
        }
        cout << numerator << '/' << denominator << endl;
    }
    return 0;
}

【问题讨论】:

  • 如果您访问此类站点的目标是学习 C++,我建议您立即停止。而是get a few good books 并向他们学习。你至少犯了一本好书应该告诉你不要做的基本错误:全局变量。全局变量,尤其是当您不需要在函数之间共享数据时,是一种不好的做法。
  • 适当注明。谢谢。我编辑了我的代码以摆脱它们。我的目标不是学习 C++。我已经很清楚了。这只是我不明白是什么让我的输出对调试器正确但对法官不正确
  • 在线评委不仅仅针对他们向您公开的“演示测试用例”测试您的代码,他们只是示例。但它也会针对一些扩展问题测试您的代码,例如,给它大量数字并测试您的代码以不通过内存/时间限制。因此,请确保您的代码确实可以扩展,并且您可以处理问题测试所涵盖的极端情况。
  • k &lt;= sqrt(i); 可以改进。评估一次,最好还是使用k * k &lt;= i 并防止溢出的可能性。
  • 如果你没有及时通过测试,或者你是否给出了错误的计算,法官会告诉你吗?在时间上,他们给你 3 秒(在未指定性质的 CPU 上)。该示例测试了最大的输入,因此问题不在于扩大该值。他们告诉你你会得到一个“数字系列”,但不是多少,所以如果有一个缩放点,那就是:也许这是一个非常长的系列。我绝对认为他们应该告诉你你是否超过了时间限制,提交一个只是一个无限循环的测试,并确保他们会告诉你如果是这样。

标签: c++ number-theory


【解决方案1】:

Here@jte表示可以在O(N*logN)中实现PHI的计算:

phi[0]  = phi[1] = 0;
for (int i=2; i<maxn; ++i)
    phi[i] = i - 1;
for (int i=1; i<maxn; ++i)
        for (int j=i+i; j<maxn; j+=i)
                 phi[j] -= phi[i];

我找不到您的代码的问题。可能是 TLE(超出时间限制)问题,因为您应该使用二进制搜索来查找分母。但是这段代码会被接受:

#include<bits/stdc++.h>

using namespace std;

const int N = 200031;

int pr[N+31],phi[N+31];
vector<int> P[N+31];
long long S[N+31];

int count(int n,int X)
{
    int res=n;
    int N=P[X].size();
    for (int mask=1;mask<(1<<N);mask++) {
        int C=0;
        int prod=1;
        for (int j=0;j<N;j++)
            if (mask&(1<<j))
                C++,
                prod*=P[X][j];
        if (C%2)
            res-=n/prod;
        else
            res+=n/prod;
    }
    return res;
}

int solve(int need,int val)
{
    int l,r;
    l=1;
    r=val;
    while (l<r) {
        int mid=l+r;
        mid/=2;
        int Q=count(mid,val);
        if (Q>=need)
            r=mid;
        else
            l=mid+1;
    }
    return l;
}

int main()
{
    ios_base::sync_with_stdio(0);

    pr[1]=1;
    for (int i=1;i<=N;i++) {
        if (pr[i])
            continue;
        for (int j=i;j<=N;j+=i)
            P[j].push_back(i),
            pr[j]=1;
    }

    for (int i=1;i<=N;i++) {
        phi[i]=i;
        for (int j=0;j<P[i].size();j++) {
            int val=P[i][j];
            phi[i]=phi[i]/val*(val-1);
        }
    }
    for (int i=1;i<=N;i++)
        S[i]=S[i-1]+phi[i];

    long long x;
    while (cin>>x) {
        if (x==0)
            break;
        --x;
        if (x==0)
        {
            cout<<0<<"/"<<1<<endl;
            continue;
        }
        int id=lower_bound(S+1,S+N+1,x)-S;
        x-=S[id-1];
        int ps=solve(x,id);
        cout<<ps<<"/"<<id<<endl;
    }

    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多