如何使用BIT解决这个问题?

时间:2013-06-05 15:32:18

标签: c++ algorithm math data-structures discrete-mathematics

我发现了一个很好的数学问题,但我仍然无法解决它,我试图找到一个使用谷歌的解决方案,并发现它可以使用二进制索引树数据结构解决,但解决方案对我来说并不清楚

这里的问题叫做Finding Magic Triplets,它可以在Uva在线评判中找到:

(a + b ^ 2)mod k = c ^ 3 mod k,其中a< = b< = c< = 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;
}

1 个答案:

答案 0 :(得分: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都是&lt; = 10 ^ 5所以你可以依次考虑a的每个值,b又依次考虑c和c,但如果k远小于n,你可以更聪明,因为它会是某种fiddly fence-post计数表达式,允许你计算出0..n范围内有多少数字等于每个i的i mod k。

给定这三个数组然后考虑每个可能的数字对i,j,其中0 <= i,j <1。 k并确定存在具有那些值mod k的arrayA [i] * arrayB [j]对。在arrayAB [i + j mod k]中对它们求和,以找到你可以选择a + b ^ 2 mod k = x for 0&lt; = x&lt; ķ。现在你有两个数组arrayAB和arrayC,其中arrayAB [i] * arrayC [i]是找到一个三元组的方式的数量,其中a + b ^ 2 = c ^ 3] = i,所以求全于0&lt; =我&lt; k得到你的答案。