使用K色的独特项链数量

时间:2015-07-05 12:07:18

标签: c++ algorithm math combinatorics

我的任务是在C ++中使用K色找到不同项链的数量。

  

如果其中一条项链,则认为两条项链是不同的   通过旋转第二个项链无法从第二个项链获得   任何角度的项链。   找出模数不同的项链总数(10 ^ 9 + 7)。

我认为这个公式很适合解决问题:

enter image description here

我使用C ++实现了一个程序:

#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
const int M = 1e9 + 7;

int main()
{
    long long  n, k;
    cin >> n >> k;

    long long x = 0;
    for (int i = 0; i < n; ++i) {
        x += pow(k, __gcd(i,n));
    }

    cout << (int)(((double)1/n) * x) % M;
    return 0;
}

我将我的代码粘贴到带有测试用例的程序中,但我的解决方案通过了一半的测试用例。我找不到我的错误,只看到一个测试用例。 第一个测试用例是n = 5k = 2,答案是8。 哪里可以犯错?

4 个答案:

答案 0 :(得分:4)

实际上,您的公式不正确。可在此处找到正确的:https://en.wikipedia.org/wiki/Necklace_(combinatorics)#Number_of_necklaces

我的实施只有passed all the tests

答案 1 :(得分:1)

很抱歉,如果您的公式不正确,无法帮助您,但这是您公式的正确实施

在您的代码中,循环变量properties = example.map(&:beta, &:delta, &:gamma, &:hotel) 与公式不同。您正在移动i,但公式显示为i=0,...,n-1

更新:我认为您的第i=1,2,....n行不太正确。当x += pow(k, __gcd(i,n));大于10 ^ 9 +7时,你应该采用模数,但你没有这样做。

为了使代码清晰,x+pow(k, __gcd(i,n))操作是Modulo的分配,所以你可以写

+

但是 ( a + b ) % c = ( ( a % c ) + ( b % c ) ) % c 不是Modulo的分配,所以你不能只写

/

要计算 ( a / b ) % c = ( ( a % c ) / ( b % c ) ) % c ,您必须计算

(x/y)%M

感谢@ivlad指出MMI漏洞:)

更改

    (x * MMI(y)) % M

to(这是一个完整的答案)

 for (int i = 0; i < n; ++i) {
    x += pow(k, __gcd(i,n));
 }
 cout << (int)(((double)1/n) * x) % M;

答案 2 :(得分:1)

我发现你的程序有两个问题。首先,即使powk的小值,n也会溢出。根据输入的大小(您没有给出),pow甚至在取模数之前就会溢出。您应该将pow替换为您自己的powModM % M更频繁地int powModM(int k, int n, int M) { int res = 1; for (int i = 0; i < n; ++i) { res = (res * k) % M; } return res; } 。像

这样的东西
O(log n)

虽然如果指数很大,您可能希望将其替换为使用n快速取幂的过程。

第二个更大的问题是当你除以gcd(n,10^9+7) != 1时。与加法,减法和乘法不同,模运算中的除法不能通过在普通算术中进行除法然后取模数来实现。首先,如果n,你可以除以0.(但是,因为10 ^ 9 + 7是素数,这是非常不可能的,我会忽略这个问题)。另一个更可能的问题是,在模数运算中除以n,您必须乘以1/n的倒数,这与q完全不同。

这是使用扩展欧几里德算法计算乘法逆的Java例程。您可以轻松地将其适应C ++。请注意,函数中的商public static long inverse(long a, long m) { // mult. inverse of a mod m long r = m; long nr = a; long t = 0; long nt = 1; long tmp; while (nr != 0) { long q = r/nr; tmp = nt; nt = t - q*nt; t = tmp; tmp = nr; nr = r - q*nr; r = tmp; } if (r > 1) return -1; // no inverse if (t < 0) t += m; return t; } 是通过整数除法计算的。

{{1}}

答案 3 :(得分:0)

考虑数量限制。

long long可以是unsigned long long,也可以是long double

double可以是long double。这实际上是依赖于平台的,但可能是原因。

顺便说一下,n被视为long long,它真的可能太大吗?如果是,你的循环将花费很长时间,你可能会得到“超出时间限制”。如果不是,只需声明int即可。在long long足够的时候声明它int会导致一些错误!!