Как я могу решить эту проблему с помощью BIT?

Я нашел хорошую математическую задачу, но до сих пор не могу ее решить. Я попытался найти одно решение с помощью Google и обнаружил, что его можно решить с помощью структуры данных двоичного индексированного дерева, но решение мне не ясно.

Вот Задача под названием «Поиск волшебных троек», ее можно найти в онлайн-судье Ува:

(a + b^2) mod k = c^3 mod k, где a‹=b‹=c и 1 ‹= a, b, c ‹= n.

при заданных n и k (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;
}

person user2456277    schedule 05.06.2013    source источник
comment
Не могли бы вы добавить несколько тестовых случаев, чтобы можно было проверить любое решение?   -  person Markus Jarderot    schedule 06.06.2013
comment
@MarkusJarderot [ссылка]uva.onlinejudge.org/ есть ссылка на задачу, пример для n=10 и k=7 есть 27 разных троек.   -  person user2456277    schedule 06.06.2013
comment
Так вы пытаетесь понять это решение, или оно не работает? Не совсем понятно, в чем заключается ваш вопрос.   -  person Aaron Dufour    schedule 12.06.2013
comment
да, я пытался понять это, я понял. Единственный ответ помог мне решить проблему.   -  person user2456277    schedule 14.06.2013
comment
@user2456277 user2456277 Пожалуйста, либо примите ответ ниже, либо напишите свой собственный, чтобы другие могли извлечь уроки из этого вопроса.   -  person Aaron Dufour    schedule 14.06.2013


Ответы (1)


Вы полны решимости использовать BIT? Я бы подумал, что подойдут обычные массивы. Я бы начал с создания трех массивов размером 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 по модулю k для каждого i.

Учитывая эти три массива, рассмотрим каждую возможную пару чисел i, j, где 0‹=i,j ‹ k, и выясним, что существуют пары arrayA[i] * arrayB[j], которые имеют эти значения по модулю k. Суммируйте их в arrayAB[i + j mod k], чтобы найти количество способов, которыми вы можете выбрать a + b^2 mod k = x для 0‹=x ‹ k. Теперь у вас есть два массива: arrayAB и arrayC, где arrayAB[i] * arrayC[i] — количество способов найти тройку, где a + b^2 = c^3] = i, так что суммируйте это по всем 0‹= i ‹ k, чтобы получить ответ.

person mcdowella    schedule 06.06.2013
comment
спасибо за ваш ответ, но я должен сказать, что ваше решение совершенно неверно, во-первых, потому что я предполагаю, что вы не принимаете во внимание тот факт, что a ‹= b ‹= c, а во-вторых, это неэффективно, потому что оно сложность O(K^2), если я не ошибаюсь. - person user2456277; 06.06.2013
comment
В перспективе BIT имеют log(n) сложность как для sum, так и для add, поэтому решение OP O(N*log(K)) - person Aaron Dufour; 06.06.2013
comment
Хорошо, идея похожа на эту, алгоритм начинает устанавливать b с N на 1, потому что c должно быть больше, чем b, поэтому, когда b равно N, единственное возможное значение для c также равно N, тогда b равно N-1, и c может быть N-1 или N, N уже находится в BIT, поэтому достаточно установить c=N-1 и добавить это значение в BIT, наконец, количество значений a равно len/K, что целочисленное деление обеспечивает количество каждого остатка . - person user2456277; 17.06.2013