设置位与指数模运算相结合
Set bits combined with exponential modular arithmetics
我昨天在挑战赛中遇到了这个问题。我以为我已经正确编码并且我的示例测试用例通过了。然而,甚至没有一个测试用例在后端通过。这是我的代码。请有人帮助我。挑战对我来说已经结束,所以我不能再提交了。但我想从我的错误中吸取教训。谢谢
import java.io.*;
//import java.util.*;
public class TestClass {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter wr = new PrintWriter(System.out);
int n = Integer.parseInt(br.readLine().trim());
String[] arr_a = br.readLine().split(" ");
int[] a = new int[n];
for(int i_a=0; i_a<arr_a.length; i_a++)
{
a[i_a] = Integer.parseInt(arr_a[i_a]);
}
long out_ = solve(a);
System.out.println(out_);
wr.close();
br.close();
}
static long solve(int[] a){
// Write your code here
long sum = 0l;
long MAX = 10000000011l;
long i = 1l;
for(int x : a) {
long count = 0;
while(x>0) {
x &= (x-1l);
count++;
}
long res = 1l;
long temp = i;
count = count % MAX;
while(temp > 0) {
if((temp & 1l) == 1l) {
res = (res * count) % MAX;
}
temp = temp >> 1l;
count = ((count % MAX) * (count % MAX)) % MAX;
}
long t =((sum%MAX) + (res % MAX))%MAX;
sum = t;
i++;
}
return sum;
}
}
"not even a single test case passed"有点奇怪,但我看到的唯一错误是你的exponentiation by squaring部分。
你所有的数都小于10^10 + 11
,但是这个常量多于32位,乘法时有时会溢出(因为long
是64位有符号整数).
这可以通过几种方法解决:
(a*b) % M
操作可以使用类似于您的 "exponentiation by squaring" 实现的算法来完成。您只需要用加法替换所有乘法。结果,乘法被 O(log(n))
加法和 'multiplying by 2' 运算代替。实施示例:
static long multiply(long a, long b, long M) {
long res = 0;
long d = a % M;
while (b > 0) {
if ((b & 1) == 1) {
res = (res + d) % M;
}
b >>= 1;
d = (d + d) % M;
}
return res;
}
您可以只缓存 b^i % M
个先前计算步骤的数字。对于每个设置位的数量(没有那么多),您可以保存先前计算的值和 last(b)
- 当 a[i]
有 b
设置位时的最后一个 i
.然后只需使用从 last(b) + 1
到当前索引 i
.
的线性循环计算新值
使用BigInteger进行乘法。
我昨天在挑战赛中遇到了这个问题。我以为我已经正确编码并且我的示例测试用例通过了。然而,甚至没有一个测试用例在后端通过。这是我的代码。请有人帮助我。挑战对我来说已经结束,所以我不能再提交了。但我想从我的错误中吸取教训。谢谢
import java.io.*;
//import java.util.*;
public class TestClass {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter wr = new PrintWriter(System.out);
int n = Integer.parseInt(br.readLine().trim());
String[] arr_a = br.readLine().split(" ");
int[] a = new int[n];
for(int i_a=0; i_a<arr_a.length; i_a++)
{
a[i_a] = Integer.parseInt(arr_a[i_a]);
}
long out_ = solve(a);
System.out.println(out_);
wr.close();
br.close();
}
static long solve(int[] a){
// Write your code here
long sum = 0l;
long MAX = 10000000011l;
long i = 1l;
for(int x : a) {
long count = 0;
while(x>0) {
x &= (x-1l);
count++;
}
long res = 1l;
long temp = i;
count = count % MAX;
while(temp > 0) {
if((temp & 1l) == 1l) {
res = (res * count) % MAX;
}
temp = temp >> 1l;
count = ((count % MAX) * (count % MAX)) % MAX;
}
long t =((sum%MAX) + (res % MAX))%MAX;
sum = t;
i++;
}
return sum;
}
}
"not even a single test case passed"有点奇怪,但我看到的唯一错误是你的exponentiation by squaring部分。
你所有的数都小于10^10 + 11
,但是这个常量多于32位,乘法时有时会溢出(因为long
是64位有符号整数).
这可以通过几种方法解决:
(a*b) % M
操作可以使用类似于您的 "exponentiation by squaring" 实现的算法来完成。您只需要用加法替换所有乘法。结果,乘法被O(log(n))
加法和 'multiplying by 2' 运算代替。实施示例:static long multiply(long a, long b, long M) { long res = 0; long d = a % M; while (b > 0) { if ((b & 1) == 1) { res = (res + d) % M; } b >>= 1; d = (d + d) % M; } return res; }
您可以只缓存
b^i % M
个先前计算步骤的数字。对于每个设置位的数量(没有那么多),您可以保存先前计算的值和last(b)
- 当a[i]
有b
设置位时的最后一个i
.然后只需使用从last(b) + 1
到当前索引i
. 的线性循环计算新值
使用BigInteger进行乘法。