hdu 5116 计数

题目大意:给你n个点, n个点的坐标都在200以内,让你统计不相交的两个L形的种数,且L形的两条边长的gcd = 1。

思路:用二维树状数组维护点的信息,然后划分区块进行统计,题解是用总的减去相交的,不需要用到二维树状数组。

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define pii pair<int, int>

using namespace std;

const int N = 200 + 7;
const int M = 1e4 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 +7;
const double eps=1e-6;
const double pi=acos(-1);

int n, m, up[N][N], rt[N][N];
LL cnt[N][N], num[N][N];
bool Map[N][N];

struct BIT  {
    LL a[N][N];
    void modify(int x, int y, LL v) {
        for(int i = x; i < N; i += i & -i)
            for(int j = y; j < N; j += j & -j)
                a[i][j] += v;
    }

    LL sum(int x, int y) {
        LL ans = 0;
        for(int i = x; i; i -= i & -i)
            for(int j = y; j; j -= j & -j)
                ans += a[i][j];
        return ans;
    }

    void init() {
        memset(a, 0, sizeof(a));
    }
}bit1, bit2;

void init() {
    for(int i = 1; i < N; i++) {
        for(int j = 1; j < N; j++) {
            cnt[i][j] = cnt[i][j - 1] + (__gcd(i, j) == 1);
        }
    }

    for(int i = 1; i < N; i++) {
        for(int j = 1; j < N; j++) {
            for(int k = 1; k <= i; k++) {
                num[i][j] += cnt[k][j];
            }
        }
    }
}

int main() {
    init();
    int T; scanf("%d", &T);
    for(int cas = 1; cas <= T; cas++) {
        bit1.init(); bit2.init();
        memset(rt, 0, sizeof(rt));
        memset(up, 0, sizeof(up));
        memset(Map, 0, sizeof(Map));

        scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            int x, y; scanf("%d%d", &x, &y);
            Map[x][y] = true;
        }

        for(int i = 200; i >= 1; i--) {
            for(int j = 200; j >= 1; j--) {
                if(Map[i][j]) {
                    up[i][j] = up[i + 1][j] + 1;
                    rt[i][j] = rt[i][j + 1] + 1;
                }
            }
        }

        LL ans = 0;

        for(int i = 200; i >= 1; i--) {
            for(int j = 1; j <= 200; j++) {
                if(!Map[i][j] || up[i][j] <= 1 || rt[i][j] <= 1) continue;
                ans += num[up[i][j] - 1][rt[i][j] - 1] * (bit2.sum(200, 200) - bit2.sum(i + up[i][j] - 1, j));

                int q = i + up[i][j] - 1;
                for(int k = i + 1; k <= 200 && k <= q; k++) {
                    ans += cnt[k - i][rt[i][j] - 1] * (bit2.sum(q, j) - bit2.sum(k, j));
                    ans += cnt[k - i][rt[i][j] - 1] * (bit1.sum(k, j - 1));
                }

                bit2.modify(i, j, num[up[i][j] - 1][rt[i][j] - 1]);
                for(int k = j + 1; k <= 200 && k < j + rt[i][j]; k++) {
                    bit1.modify(i, k, cnt[k - j][up[i][j] - 1]);
                }
            }
        }

        printf("Case #%d: %lld
", cas, 2 * ans);
    }
    return 0;
}


/*
*/
原文地址:https://www.cnblogs.com/CJLHY/p/9309930.html