码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces 870E Points, Lines and Ready-made Titles

时间:2018-10-31 00:02:17      阅读:215      评论:0      收藏:0      [点我收藏+]

标签:val   img   nbsp   opera   info   accept   ++   width   typename   

题目传送门

  传送门I

  传送门II

  传送门III

题目大意

  平面上有$n$个点,第$i$个点可以画一条平行于$y$轴且经过这个点的直线或者平行于$x$轴且经过这个点的直线或者什么都不做,问能够产生多少种本质不同的图案。

  考虑每个点与它$x$坐标相同且$y$坐标比它大的第一个点连一条无向边,以及与它$y$坐标相同且$x$坐标第一个比它大的点连一条无向边。

  显然,每个连通块和连通块之间互不影响,所以分别考虑每个连通块。

  设当前连通块所有点的横坐标构成的集合为$X$,纵坐标构成的集合为$Y$。

  • 如果点数等于边数减一,只有对于包含所有满足$x = x_i\vee y = y_i , x_i \in X, y_i \in Y$的直线的图案无法画出,其他图案都能画出。(这里的所有图案指,图案中包含的任意一条直线一定经过这中间某个点的所有图案)
    我们考虑用归纳法来证明它。假设新增的点的坐标是$(x_0, y_0)$
    • 当$|V| = 1$的时候显然成立。
    • 假设当$|V| = k - 1$的时成立,考虑加入一个叶节点。
      显然我们只需要证明直线数为$|X| + |Y| - 1$的所有图案都能画出。(其它的只需要选一个这样的图案,然后点一些点不操作就行了)
      • 假设新增加了一个横坐标$x_0$,那么考虑我们点当前这个点,画一条直线$x = x_0$,这样所有不存在的直线不是$x = x_0$的图案都可以画出了。
        技术分享图片

        (其中蓝色虚线表示不存在的直线,紫色表示前$k - 1$个点选择的直线,绿色表示第$k$个点选择的直线,红点是第$k$个点)

      • 考虑如果不存在直线$x = x_0$的图案,那么对于前$k - 1$个点,我们找一个不存在直线$y = y_0$的方案,然后过这个点画一条直线$y = y_0$。
        技术分享图片
  • 对于点数大于等于边数,我们考虑它的任意一个生成基环树。
    任意删去环上的一个点,剩下一堆树,根据以上结论,我们可以构造出一个包含所有满足$x = x_i\vee y = y_i , x_i \in X, y_i \in Y$的图案(先让树上某个直线画不了,然后这个新点去补锅,剩下的树可以用归纳法,不断添加叶节点来证明)。

   所以当一个连通块是树的时候方案数为$2^{|X| + |Y|} - 1$,否则是$2^{|X| + |Y|}$。

Code

  1 /**
  2  * Codeforces
  3  * Problem#870E
  4  * Accepted
  5  * Time: 93ms
  6  * Memory: 9800k
  7  */
  8 #include <algorithm>
  9 #include <iostream>
 10 #include <cstdlib>
 11 #include <cstdio>
 12 #include <set>
 13 using namespace std;
 14 typedef bool boolean;
 15 
 16 template <typename T>
 17 void pcopy(T* pst, const T* ped, T* pval) {
 18     for ( ; pst != ped; *(pst++) = *(pval++));
 19 }
 20 
 21 typedef class Point {
 22     public:
 23         int x, y, id;
 24 
 25         Point(int x = 0, int y = 0, int id = 0):x(x), y(y), id(id) {}
 26 }Point;
 27 
 28 typedef class union_found {
 29     public:
 30         int n;
 31         int *f;
 32         int *dif;    // |E| - |V|
 33 
 34         union_found() {    }
 35         union_found(int n):n(n) {
 36             f = new int[(n + 1)];
 37             dif = new int[(n + 1)];
 38             for (int i = 1; i <= n; i++)
 39                 f[i] = i, dif[i] = -1;    
 40         }
 41 
 42         int find(int x) {
 43             return (f[x] == x) ? (x) : (f[x] = find(f[x]));
 44         }
 45 
 46         void unit(int u, int v) {
 47             int fu = find(u), fv = find(v);
 48             if (fu == fv) {
 49                 dif[fu]++;
 50                 return;
 51             }
 52             dif[fu] += dif[fv] + 1;
 53             f[fv] = fu;
 54         }
 55 
 56         int operator [] (int u) {
 57             return find(u);
 58         }
 59 
 60         int operator () (int u) {
 61             return dif[u];
 62         }
 63 }union_found;
 64 
 65 const int M = 1e9 + 7;
 66 
 67 int add(int a, int b) {
 68     return ((a += b) >= M) ? (a - M) : (a);
 69 }
 70 
 71 int mul(int a, int b) {
 72     return a * 1ll * b % M;
 73 }
 74 
 75 int sub(int a, int b) {
 76     return ((a -= b) < 0) ? (a + M) : (a);
 77 }
 78 
 79 int qpow(int a, int p) {
 80     int pa = a, rt = 1;
 81     for ( ; p; p >>= 1, pa = mul(pa, pa))
 82         if (p & 1)
 83             rt = mul(rt, pa);
 84     return rt;
 85 }
 86 
 87 int n;
 88 Point* ps;
 89 set<int> *sx, *sy;
 90 union_found dsu;
 91 
 92 inline void init() {
 93     scanf("%d", &n);
 94     ps = new Point[(n + 1)];
 95     for (int i = 1, x, y; i <= n; i++) {
 96         scanf("%d%d", &x, &y);
 97         ps[i] = Point(x, y, i);
 98     }
 99 }
100 
101 inline void solve() {
102     dsu = union_found(n);
103     sort(ps + 1, ps + n + 1, [&] (const Point& a, const Point& b) {    return (a.x ^ b.x) ? (a.x < b.x) : (a.y < b.y);    });
104     for (int i = 1, j, x; i <= n; i = j) {
105         for (x = ps[i].x, j = i + 1; j <= n && ps[j].x == x; j++);
106         for (int k = i; k < j; k++)
107             if (k + 1 < j)
108                 dsu.unit(ps[k].id, ps[k + 1].id);
109     }
110 
111     for (int i = 1; i <= n; i++)
112         swap(ps[i].x, ps[i].y);
113     sort(ps + 1, ps + n + 1, [&] (const Point& a, const Point& b) {    return (a.x ^ b.x) ? (a.x < b.x) : (a.y < b.y);    });
114     for (int i = 1, j, x; i <= n; i = j) {
115         for (x = ps[i].x, j = i + 1; j <= n && ps[j].x == x; j++);
116         for (int k = i; k < j; k++)
117             if (k + 1 < j)
118                 dsu.unit(ps[k].id, ps[k + 1].id);
119     }
120 
121     sx = new set<int>[(n + 1)];
122     sy = new set<int>[(n + 1)];
123     for (int i = 1, p; i <= n; i++) {
124          p = ps[i].id;
125          sx[dsu[p]].insert(ps[i].x);
126          sy[dsu[p]].insert(ps[i].y);
127     }
128     int res = 1;
129     for (int i = 1; i <= n; i++) {
130         if (dsu[i] == i)
131             res = mul(res, sub(qpow(2, sx[i].size() + sy[i].size()), (dsu(i) < 0)));
132     }
133     printf("%d\n", res);
134 }
135 
136 int main() {
137     init();
138     solve();
139     return 0;
140 }

 

Codeforces 870E Points, Lines and Ready-made Titles

标签:val   img   nbsp   opera   info   accept   ++   width   typename   

原文地址:https://www.cnblogs.com/yyf0309/p/9873974.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!