Установить биты в сочетании с экспоненциальной модульной арифметикой
Я получил этот вопрос вчера в вызове. Я думал, что закодировал это правильно, и мой пример теста был пройден. Однако ни один тестовый пример не прошел на бэкэнде. Вот мой код Пожалуйста, кто-нибудь, помогите мне. Задача для меня окончена, и я не могу представить ее дальше. Но я хочу учиться на своих ошибках. Благодарю.
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;
}
}
1 ответ
Немного странно, что "даже ни один тестовый пример не пройден", но единственная ошибка, которую я вижу, это ваше возведение в квадрат по квадратуре.
Все ваши номера меньше 10^10 + 11
, но эта константа имеет более 32 бит, и когда вы умножаете, вы иногда получаете переполнение (потому что long
64-разрядное целое число со знаком).
Это можно исправить несколькими подходами:
(a*b) % M
Операция может быть выполнена с помощью алгоритма, аналогичного вашей реализации "возведение в квадрат". Вам просто нужно заменить все умножения на дополнения. В результате умножение заменяется наO(log(n))
операции сложения и умножения на 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)
- последнийi
когдаa[i]
имелb
установить биты. Затем просто вычислите новое значение с помощью линейного цикла изlast(b) + 1
до текущего индексаi
,Используйте BigInteger для умножения.