我的任务是在C ++中使用K色找到不同项链的数量。
如果其中一条项链,则认为两条项链是不同的 通过旋转第二个项链无法从第二个项链获得 任何角度的项链。 找出模数不同的项链总数(10 ^ 9 + 7)。
我认为这个公式很适合解决问题:
我使用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 = 5
和k = 2
,答案是8
。
哪里可以犯错?
答案 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)
我发现你的程序有两个问题。首先,即使pow
和k
的小值,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
会导致一些错误!!