求一个数的排列的gcd

Finding gcd of permutations of a Number

本文关键字:排列 gcd 一个      更新时间:2023-10-16

这是问题的链接:

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

考虑自然数N的十进制表示。找出所有数字的最大公约数(GCD),这些数字可以通过排列给定数字中的数字来获得。允许前导零。

我采用了以下方法:https://math.stackexchange.com/a/22453

首先,如果所有数字都相同,那么只有一个数字,那就是GCD。如前所述,如果3或9是一个排列的因子,那么它将是所有排列的因子。否则,想象一下,当1和10位数不同时,只交换它们。这两者的GCD必须除以100a+10b+c−100a+10c+b=9(b−c),其中b和c是个位数。为了使所有数字的GCD具有因子2,所有数字必须是偶数。对于因子为4的GCD,所有数字必须为0、4或8,对于8,它们必须为0或8。5和7也是如此。最后,如果所有数字都是0、3、6或9,则GCD将为27,并且27划分一个排列,并且如果所有数字是0或9,并且81划分一个置换,则为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。我似乎找不到任何可能出错的边缘案例。

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

首先,如果所有数字都相同,那么只有一个数字,那就是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;
}