查找数字排列的gcd

时间:2014-09-06 09:13:04

标签: c++ math largenumber greatest-common-divisor

以下是问题的链接:

http://www.spoj.com/problems/GCD/

  

考虑自然数N的十进制表示。   找到通过置换给定数字中的数字可以获得的所有数字的最大公约数(GCD)。允许前导零。

我致力于以下方法: https://math.stackexchange.com/a/22453

  

首先,如果所有数字都相同,则只有一个数字,即GCD。正如之前所指出的,如果3或9是一个排列因子,它将是它们的一个因素。否则,想象一下当它们不同时只交换那些和十位数。这两者的GCD必须除以100a + 10b + c-100a + 10c + b = 9(b-c),其中b和c是单个数字。对于具有因子2的所有数字的GCD,所有数字必须是偶数。对于GCD具有因子4,所有数字必须是0,4或8,对于8,它们必须是0或8.类似地,对于5和7.最后,如果所有数字都是0,则GCD将是27,如果所有数字都是0或9并且81除以一个排列,则3,6或9和27除以一个排列,81除以一个排列。你能证明最后的断言吗?

我的解决方案: http://ideone.com/VMUb6w

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<string>



using namespace std;

int rem(string str, int a){
    if (str.empty())
    {
        return 0;
    }
    int temp = (str[str.length() - 1] - '0') % a;
    int temp2 = 10 % a;
    str.erase(str.length() - 1);
    int temp3 = (rem(str, a)*temp2) % a;
    return (temp3 + temp) % a;
}


int gcdf(int a, int b)
{
    return b ? gcdf(b, a%b) : a;
}


int main(){
    string str;
    while (cin >> str)
    {

    size_t l = str.length();
    vector<int> digit;
    int sum = 0;
    int frequency[9];
    for (int i = 0; i<9; i++)
        frequency[i] = 0;
    int zero_sum = 0;
    for (size_t i = 0; i < l; i++)
    {
        if (str.at(i) != '0')
        {
            frequency[str.at(i) - '1']++;
            sum += str.at(i) - '0';
        }
        else
        {
            zero_sum++;
        }
    }

    for (size_t i = 0; i < 9; i++)
    {
        if (frequency[i])
        {
            digit.push_back(i + 1);
        }
    }
    int gcds = 0, gcd = 1;
    for (size_t i = 0; i < digit.size(); i++)
    {
        gcds = gcdf(digit[i], gcds);
    }
    if (gcdf(3, gcds) == 1)
    {
        gcd *= gcds;
    }
    if (gcds == 6)
    {
        gcd *= 2;
    }
    if ((rem(str, 81) == 0) && (gcdf(gcds, 3) == 3))
    {
        gcd *= 81;
    }
    else
    {
        if ((rem(str, 27) == 0) && (gcdf(gcds, 3) == 3))
        {
            gcd *= 27;
        }
        else
        {
            if (sum % 9 == 0)
            {
                gcd *= 9;
            }
            else
            {
                if (sum % 3 == 0)
                {
                    gcd *= 3;
                }
            }
        }
    }
    if((digit.size()==1)&&(zero_sum==0))
            cout<<str;
    else            
         cout << gcd << endl;


}
return 0;
}

但它正在给WA。 我似乎找不到任何可能出错的边缘情况。

请告诉我哪里错了。谢谢:))

1 个答案:

答案 0 :(得分:0)

  

首先,如果所有数字都相同,则只有一个数字,即GCD。

你不处理这个(第一个)案件

因此,对于您的代码1111144给出了错误答案。

  

[..] 81如果所有数字都是0或9且81除以一个排列。

您的测试似乎是错误的:

if ((rem(str, 81) == 0) && (gcdf(gcds, 3) == 3))

你的意思是:

if ((rem(str, 81) == 0) && (gcdf(gcds, 9) == 9))

所以

你有3699个不一致结果的排列:

27 for 3699, 3996, 6939, 6993, 9369, 9693, 9936
81 for 3969, 6399, 9396, 9639, 9963.

我要检查的实现(对于int号)是:

int my_gcd(std::string str)
{
    std::sort(str.begin(), str.end());
    std::string first = str;
    int gcd = atoi(first.c_str());

    while (std::next_permutation(str.begin(), str.end())) {
        gcd = gcdf(atoi(str.c_str()), gcd);
    }
    return gcd;
}