Я нашел хорошую математическую задачу, но все еще не могу ее решить, я попытался найти одно решение с помощью Google и обнаружил, что это можно решить с помощью структуры данных Binary Indexed Tree, но решение мне не ясно.
Вот проблема под названием «Поиск магических тройняшек», ее можно найти в онлайн-суде по Uva:
(a + b ^ 2) mod k = c ^ 3 mod k, где a<= Ь<= с и 1 <= а, б, в <= п.
учитывая п и к (1 <= n, k <= 10 ^ 5), сколько разных магических триплетов существует для известных значений n и k. Триплет отличается от другого, если любое из трех значений не одинаково в обоих триплетах.
и вот решение, которое я нашел:
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long int64;
const int MAX_K = (int)(1e5);
int N, K;
struct BinaryIndexedTree{
typedef int64 bit_t;
static const int MAX_BIT = 3*MAX_K + 1;
bit_t data[MAX_BIT+1];
int SIZE;
void init(int size){
memset(data, 0, sizeof(data));
SIZE = size;
}
bit_t sum(int n){
bit_t ret = 0;
for(;n;n-=n&-n){
ret += data[n];
}
return ret;
}
bit_t sum(int from, int to){
return sum(to)-sum(from);
}
void add(int n, bit_t x){
for(n++;n<=SIZE;n+=n&-n){
data[n]+=x;
}
}
};
BinaryIndexedTree bitree;void init(){
scanf("%d%d", &N, &K);
}
int64 solve(){
bitree.init(2*K+1);
int64 ans = 0;
for(int64 i=N; i>=1; i--){
int64 b = i * i % K, c = i * i * i % K;
bitree.add(c, 1);
bitree.add(c+K, 1);
bitree.add(c+2*K, 1);
int64 len = i;
if(len >= K){
ans += (len / K) * bitree.sum(K);
len %= K;
}
if(len > 0){
ans += bitree.sum(b + 1, b + len + 1);
}
}
return ans;
}
int main(){
int T;
scanf("%d", &T);
for(int i=0; i<T; i++){
init();
printf("Case %d: %lld\n", i+1, solve());
}
return 0;
}
Вы полны решимости использовать биты? Я бы подумал, что обычные массивы подойдут. Я бы начал с создания трех массивов размера k, где arrayA [i] = количество значений a в диапазоне, равном i mod k, arrayB [i] = количество значений b в диапазоне, где b ^ 2 = i mod k и arrayC [i] = количество значений c в диапазоне, где c ^ 3 = i mod k. N и k оба <= 10 ^ 5, чтобы вы могли просто рассмотреть каждое значение a по очереди, b по очереди и c по очереди, хотя вы можете быть умнее, если k намного меньше, чем n, потому что это будет своего рода нечеткое выражение для подсчета столбов это позволяет вам определить, сколько чисел в диапазоне 0..n равно i mod k для каждого i.
Учитывая эти три массива, рассмотрим каждую возможную пару чисел i, j, где 0<= I, J < k и выяснить, что есть пары arrayA [i] * arrayB [j], которые имеют эти значения mod k. Суммируйте их в массиве AB [i + j mod k], чтобы найти количество способов, которыми вы можете выбрать a + b ^ 2 mod k = x для 0<= х < к. Теперь у вас есть два массива arrayAB и arrayC, где arrayAB [i] * arrayC [i] — это число способов найти тройку, где a + b ^ 2 = c ^ 3] = i, так что суммируйте это по всем 0<= я < K, чтобы получить ваш ответ.
Других решений пока нет …