2013 Multi-University Training Contest 10

HDU-4698 Counting

题意:给定一个二维平面,其中x取值为1-N,y取值为1-M,现给定K个点,问至少包括K个点中的一个的满足要求的<Xmin, Xmax, Ymin, Ymax>共有多少中取值情况。也就是说K个点中至少一个点落在所给定的区间内。

解法:正面求解,由于点只有1000个,因此直接暴力离散化之后的x轴坐标,对于y轴则可以通过增加一个一个加入点,使用一个set来维护纵轴有多少种不同的取法。

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
using namespace std;

typedef long long LL;
const int N = 1005;
const int mod = int(1e9)+7;
const int inf = 0x7fffffff;
struct Point {
    int x, y;
    Point() {}
    Point(int _x, int _y) : x(_x), y(_y) {}
    bool operator < (const Point &t) const {
        if (x != t.x) return x < t.x;
        else return y < t.y;
    }
}p[N];
int n, m, K;
int val[N];
set<int>st;
set<int>::iterator it1, it2;

int main() {
    while (scanf("%d %d %d", &n, &m, &K) != EOF) {
        for (int i = 1; i <= K; ++i) {
            scanf("%d %d", &p[i].x, &p[i].y);
            val[i] = p[i].x;
        }
        sort(p+1, p+K+1);
        sort(val+1, val+1+K);
        int cnt = unique(val, val+K+1)-val; // 去重之后的x轴坐标
        val[0] = 0; val[cnt++] = n+1;
        LL ret = 0;
        for (int i = 1; i < cnt-1; ++i) {
            st.clear(); st.insert(0); st.insert(m+1);
            LL sum = 0;
            for (int j = i; j < cnt-1; ++j) {
                int left  = lower_bound(p+1, p+1+K, Point(val[j], 0))-p;
                int right = upper_bound(p+1, p+1+K, Point(val[j], inf))-p;
                for (int k = left; k < right; ++k) { // x轴取值为val[j]的点一次性取出来 
                    if (st.count(p[k].y)) continue;
                    st.insert(p[k].y);
                    it1 = it2 = st.find(p[k].y);
                    it1--, it2++; // 找前一个和后一个 
                    sum = (sum+1LL*(p[k].y-*(it1))*(*(it2)-p[k].y)%mod)%mod; // 新增加的y值对,统计只跨过该点的 
                }
                ret = (ret+sum*(val[i]-val[i-1])%mod*(val[j+1]-val[j])%mod)%mod
            }
        }
        printf("%I64d
", ret);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Lyush/p/3278631.html