【发布时间】:2017-12-18 12:24:57
【问题描述】:
This 是 SPOJ 的问题。我得到 TLE。需要帮助来提高它的时间复杂度。我知道有一个测试用例会失败。但我会在时间复杂度降低后处理它。
瓢虫艾达和她的朋友一起旅行。他们每人在那里买了一件纪念品。由于他们都是数学家,所以每个人都买了一个数字。他们想修改数字以在彼此之间建立某种联系。他们决定修改他们的 GCD 大于 1 的数字(gcd(a1,a2,a3,...,aN) > 1)。无论如何,改变一个数字并不容易 - 他们唯一能做的就是去找一位数学教授,他可以将数字 A 变成数字 A+1 或 A-1 。由于这种操作并不便宜,他们希望尽量减少这种操作的数量。一个数字可以伪造任意多次。
注意:gcd(a,0)==a(所以两个 0 的 gcd 也是 0)
输入
第一行包含一个整数1 ≤ N ≤ 3*10^5,即在旅途中的朋友的数量(以及数字的数量)。
第二行包含N个整数0 ≤ a_i ≤ 10^6
输出
用最少的操作打印一行以在所有数字之间建立连接。
输入示例
5
3 9 7 6 31
示例输出
2
示例输入 2
9
3 4 5 7 8 9 11 12 13
示例输出 2
6
示例输入 3
5
7 7 11 17 1
示例输出 3
5
方法
首先我在给定的数字数组
(using function findPrimes())中找到直到(largest/2 + 1)元素的素数。然后对于数组中的每个元素,找出每个素数需要多少个operations作为其除数。每个素数的最小总和,我正在打印作为解决方案。
代码
import java.io.*;
public class Main
{
public static void main(String[] args) throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int largest = Integer.MIN_VALUE;
int n = Integer.parseInt(br.readLine());
int[] arr = new int[n];
String[] strArr = br.readLine().split(" ");
for(int i = 0 ; i < n ; i++)
{
arr[i] = Integer.parseInt(strArr[i]);
if(arr[i] > largest)
{
largest = arr[i];
}
}
func(n,arr,largest);
}
public static void func(int n,int[] arr,int largest)
{
int[] primes = findPrimes(largest / 2 + 1);
//int[] primes = findPrimes((int)Math.sqrt(largest));
int lenOfPrimes = primes.length;
int[] mat = new int[lenOfPrimes];
for(int j = 0 ; j < lenOfPrimes ; j++)
{
if(arr[0] < primes[j])
{
mat[j] = primes[j] - arr[0];
}
else if(arr[0] % primes[j] == 0)
{
mat[j] = 0;
}
else
{
int rem = arr[0] % primes[j];
mat[j] = Math.min(rem,primes[j] - rem);
}
}
for(int i = 1 ; i < n ; i++)
{
for(int j = 0 ; j < lenOfPrimes ; j++)
{
if(arr[i] < primes[j])
{
mat[j] = mat[j] + primes[j] - arr[i];
}
else if(arr[i] % primes[j] == 0)
{
mat[j] = mat[j] + 0;
}
else
{
int rem = arr[i] % primes[j];
mat[j] += Math.min(rem,primes[j] - rem);
}
}
}
int smallest = Integer.MAX_VALUE;
for(int i = 0 ; i < lenOfPrimes ;i++)
{
if(mat[i] < smallest)
smallest = mat[i];
}
System.out.println(smallest);
}
public static int[] findPrimes(int upto)
{
boolean[] primes = new boolean[upto + 1];
for(int i = 0 ; i < upto + 1 ; i++)
primes[i] = true;
int count = 0;
primes[0] = primes[1] = false;
int limit = (int)Math.sqrt(upto + 1);
for(int i = 2 ; i < upto + 1; i++)
{
if(primes[i] == true)
{
count++;
if(i <= limit)
{
for(int j = i * i ; j < upto + 1 ; j += 2 * i)
{
primes[j] = false;
}
}
}
}
int[] primeContainer = new int[count];
int index = 0;
for(int i = 2 ; i < upto + 1 ; i++)
{
if(primes[i] == true)
{
primeContainer[index++] = i;
if(index == count)
break;
}
}
return primeContainer;
}
}
【问题讨论】:
-
你应该解释你的代码背后的逻辑和思考。
-
这里有一个提示:看看 a_i mod 2。现在,要使它们都被 2 整除需要多少次操作?现在看看 a_i mod 3,...
-
我已经添加了我的方法。你是想传达相同的还是不同的东西?
-
更多Code Review。
-
@JoopEggen 绝对不是:“我知道有一个测试用例会失败。”听起来代码没有按预期工作,因此不适合代码审查。
标签: java algorithm math number-theory