Bzoj4558:分类讨论 计算几何 组合数学

国际惯例的题面:

这题让我爆肝啦......
这种计数显然容斥,正好不含任何坏点的我们不会算,但是我们能算至少含零个坏点的,至少含一个坏点的,至少含两个坏点的......
所以最终的答案就是(至少含零个坏点的-至少含一个坏点的+至少含两个坏点的-至少含三个坏点的+至少含四个坏点的)。
然后就是怎么计算的问题。
对于至少含零个坏点的,我们不妨设定所有点都是好点。
对于非正放的正方形,我们能找到一个正好包含它的最小的正放的正方形,显然这样的正方形是唯一的。


然后我们让四个点在这个正方形的边上滑动,显然这四个点的每一组位置对应一个非正放的正方形(虽然正好在四个角上的是正放的)。
于是我们可以得出总方案数为sigma( i from 1 to min(n,m) ) i * ( n - i + 1 ) * ( m - i + 1 ) 。
这个东西可以O(n)计算。

对于正好有一个坏点的,我们考虑某个以某个个点P为角的正方形A,点P一定包含这个正方形A的最小正放正方形的角上或边上。


于是我们枚举这样的正方形和点P能在的位置数量就好了。
对于点P的状态,我们计算出它距离左边界的距离l,右边界距离r,上边界距离h。


然后我们令t=min(l+r,h)。
如果我们不考虑有一些位置不能取到的话,答案应该为t*(t+3)/2。
然而这样计算了一些不能取到的位置。当t>l时,我们多计算的位置数量为(t-l)*(t-l+1)/2。(手玩一下就明白了)
t>r时同理。这样我们就能O(k)计算出至少含一个坏点的方案数。

对于正好含两及以上个坏点的,我们枚举两个坏点,显然一个正方形给你两个点,他的位置就基本确定了。


我们可以分类讨论三种情况,用向量计算出另外两个点应该在的位置。注意某些情况下以这两个点为对角线的正方形可能不在格点上。
然后对于含两个的,我们直接计算可行的正方形数;对于含三个的,我们当另外两个点有一个为坏点时计算;含四个的,我们当另外两个点均为坏点时计算。
显然含三个和含四个的我们算重了。所以应该分别除以C(3,2)和C(4,2)。

然后累加一下答案就好。
(然而计算垂直向量时没有加负号让我调了半天,老年选手身败名裂)
代码:

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<tr1/unordered_set>
  4 using namespace std;
  5 using namespace tr1;
  6 typedef long long int lli;
  7 using namespace std;
  8 using namespace tr1;
  9 const int maxp=2e3+1e2;
 10 const int mod=1e8+7;
 11
 12 struct Point {
 13     int x,y;
 14     friend bool operator < (const Point &a,const Point &b) {
 15         return a.x != b.x ? a.x < b.x : a.y < b.y;
 16     }
 17     friend Point operator - (const Point &a,const Point &b) {
 18         return (Point){a.x-b.x,a.y-b.y};
 19     }
 20     friend Point operator + (const Point &a,const Point &b) {
 21         return (Point){a.x+b.x,a.y+b.y};
 22     }
 23     friend Point operator * (const Point &a,const int &b) {
 24         return (Point){a.x*b,a.y*b};
 25     }
 26     friend Point operator / (const Point &a,const int &b) {
 27         return (Point){a.x/b,a.y/b};
 28     }
 29     inline Point swp() const {
 30         return (Point){y,-x};
 31     }
 32     inline bool candiv() const {
 33         return ( ! ( x & 1 ) ) && ( ! ( y & 1 ) );
 34     }
 35 }pt[maxp];
 36 unordered_set<lli> st;
 37 int n,m,t;
 38 lli ans,ini,sig,dou,tri,qua;
 39
 40 inline void insert(const Point &p) {
 41     lli h = (lli) p.x * ( m + 1 ) + p.y;
 42     st.insert(h);
 43 }
 44 inline bool inside(const Point &p) {
 45     return 0 <= p.x && p.x <= n && 0 <= p.y && p.y <= m;
 46 }
 47 inline bool legal(const Point &pa,const Point &pb) {
 48     return inside(pa) && inside(pb);
 49 }
 50 inline bool have(const Point &p) {
 51     lli h = (lli) p.x * ( m + 1 ) + p.y;
 52     return st.find(h) != st.end();
 53 }
 54 inline lli calcini(lli n,lli m) {
 55     lli ret = 0 , lim = min( n , m );
 56     for(lli i=1;i<=lim;i++) ret = ( ret + ( n - i + 1 ) % mod * ( m - i + 1 ) % mod * i % mod ) % mod;
 57     return ret;
 58 }
 59 inline lli calcedge(const lli &l,const lli &r,const lli &h) {
 60     lli t = min( l + r , h );
 61     if( !t ) return 0;
 62     lli ret = ( t * ( t + 3 ) >> 1 ) % mod;
 63     if( t > l ) ret -= ( ( t - l ) * ( t - l + 1 ) >> 1 ) % mod;
 64     if( t > r ) ret -= ( ( t - r ) * ( t - r + 1 ) >> 1 ) % mod;
 65     return ( ret % mod + mod ) % mod;
 66 }
 67 inline lli calcsingle(lli x,lli y) {
 68     const lli a = n - x , b = m - y , c = x , d = y;
 69     lli ret = ( calcedge(d,b,a) + calcedge(d,b,c) + calcedge(a,c,b) + calcedge(a,c,d) ) % mod;
 70     ret -= ( min(a,b) + min(b,c) + min(c,d) + min(d,a) ) % mod;
 71     return ( ret % mod + mod ) % mod;
 72 }
 73 inline lli calcdouble(const Point &a,const Point &b) {
 74     const Point delta = (a-b).swp();
 75     int ret = legal(a+delta,b+delta) + legal(a-delta,b-delta);
 76     const Point mid = a + b , pa = mid + delta , pb = mid - delta;
 77     if( pa.candiv() && pb.candiv() && legal(pa/2,pb/2) ) ++ret;
 78     return ret;
 79 }
 80 inline lli calctriple(const Point &a,const Point &b) {
 81     const Point delta = (a-b).swp();
 82     int ret = 0;
 83     if( legal(a+delta,b+delta) ) ret += have(a+delta) + have(b+delta);
 84     if( legal(a-delta,b-delta) ) ret += have(a-delta) + have(b-delta);
 85     const Point mid = a + b , pa = mid + delta , pb = mid - delta;
 86     if( pa.candiv() && pb.candiv() && legal(pa/2,pb/2) ) ret += have(pa/2) + have(pb/2);
 87     return ret;
 88 }
 89 inline lli calcquad(const Point &a,const Point &b) {
 90     const Point delta = (a-b).swp();
 91     int ret = 0;
 92     if( legal(a+delta,b+delta) ) ret += ( have(a+delta) && have(b+delta) );
 93     if( legal(a-delta,b-delta) ) ret += ( have(a-delta) && have(b-delta) );
 94     const Point mid = a + b , pa = mid + delta , pb = mid - delta;
 95     if( pa.candiv() && pb.candiv() && legal(pa/2,pb/2) ) ret += ( have(pa/2) && have(pb/2) );
 96     return ret;
 97 }
 98
 99 int main() {
100     scanf("%d%d%d",&n,&m,&t);
101     for(int i=1;i<=t;i++) scanf("%d%d",&pt[i].x,&pt[i].y) , insert(pt[i]);
102     ini = calcini(n,m);
103     for(int i=1;i<=t;i++) sig += calcsingle(pt[i].x,pt[i].y);
104     for(int i=1;i<=t;i++) for(int j=i+1;j<=t;j++) {
105         dou += calcdouble(pt[i],pt[j]) , tri += calctriple(pt[i],pt[j]) , qua += calcquad(pt[i],pt[j]);
106     }
107     tri /= 3 , qua /= 6;
108     ans = ( ( ini - sig + dou - tri + qua ) % mod + mod ) % mod;
109     printf("%lld\n",ans);
110     return 0;
111 }

原文地址:https://www.cnblogs.com/Cmd2001/p/8836894.html

时间: 2024-08-09 19:50:01

Bzoj4558:分类讨论 计算几何 组合数学的相关文章

【线段树】【分类讨论】水果姐逛水果街Ⅰ

3304 水果姐逛水果街Ⅰ 时间限制: 2 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 水果姐今天心情不错,来到了水果街. 水果街有n家水果店,呈直线结构,编号为1~n,每家店能买水果也能卖水果,并且同一家店卖与买的价格一样. 学过oi的水果姐迅速发现了一个赚钱的方法:在某家水果店买一个水果,再到另外一家店卖出去,赚差价. 就在水果姐窃喜的时候,cgh突然出现,他为了为难水果姐,给出m个问题,每个问题要求水果姐从第x家店出发到第y家店

dp+分类讨论 Gym 101128E

题目链接:http://codeforces.com/gym/101128 感觉这个人写的不错的(我只看了题目大意):http://blog.csdn.net/v5zsq/article/details/61428924 Description n个小木条,一段前面有一个小箭头,给出第一个小木条的非箭头端端点横坐标以及每个小木条箭头端的坐标,现在要从下往上把这n'个木条按顺序叠放好,要求相邻两个小木条必须有一个共同端点且有交叠部分,问小木条有多少种放法 Input 第一行一整数n表示木条数量,之

BZOJ 1067 降雨量(RMQ+有毒的分类讨论)

1067: [SCOI2007]降雨量 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 4399  Solved: 1182 [Submit][Status][Discuss] Description 我们常常会说这样的话:“X年是自Y年以来降雨量最多的”.它的含义是X年的降雨量不超过Y年,且对于任意 Y<Z<X,Z年的降雨量严格小于X年.例如2002,2003,2004和2005年的降雨量分别为4920,5901,2832和3890, 则可以说

cf 251 B Playing with Permutations 暴力 分类讨论

题链;http://codeforces.com/problemset/problem/251/B B. Playing with Permutations time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Little Petya likes permutations a lot. Recently his mom has p

BZOJ 1099([POI2007]树Drz-9次线段树&amp;分类讨论+线段树与插入顺序维护2个参数)

1099: [POI2007]树Drz Time Limit: 15 Sec  Memory Limit: 162 MB Submit: 142  Solved: 55 [Submit][Status] Description CDQZ是一个偏远的小学校,FGD在学校里中了一排树.他却不喜欢这些树的顺序,因为他们高高矮矮显得那么参差不齐. FGD定义这些树的不整齐程度为相邻两树的高度差的和.设树高分别为h1,h2,h3,-,hn.那么不整齐程度定义为:|h1-h2|+|h2-h3|+--+|hn

POJ 2826 An Easy Problem?!(线段相交,分类讨论)

题意:给两个线段,问他们能收集到多少雨水. 链接:http://poj.org/problem?id=2826 解法:分四种情况讨论 1. 存在一个线段与x轴平行,答案为0 2. 两个线段没有交点,答案为0 3. 1和2都不满足时,令线段1为比较低的那个线段,且p1为其比较高的那个点,若该点往y轴正方向的射线与线段2有交点,则答案为0 4. 3不满足时,求出两线段交点x1,p1做一条平行于x轴的线,该线与线段2的交点x2,则三角形x1, x2, p1的面积就是答案 小结:此题属于分类讨论型的题,

Codeforces 460D Little Victor and Set --分类讨论+构造

题意:从区间[L,R]中选取不多于k个数,使这些数异或和尽量小,输出最小异或和以及选取的那些数. 解法:分类讨论. 设选取k个数. 1. k=4的时候如果区间长度>=4且L是偶数,那么可以构造四个数(L,L+1,L+2,L+3),这样的话(L^(L+1)) ^ ((L+2)^(L+3)) = 0,最优 如果L不是偶数,那么看从L+1到R有没有四个数,如果有则取该四个数,否则最小异或和达不到0,也达不到1了,不再考虑k=4,k=3时还有可能等于0,所以转到k=3 2. k=3时,要使异或和为0,那

【树链剖分】【dfs序】【LCA】【分类讨论】Codeforces Round #425 (Div. 2) D. Misha, Grisha and Underground

一棵树,q次询问,每次给你三个点a b c,让你把它们选做s f t,问你把s到f +1后,询问f到t的和,然后可能的最大值是多少. 最无脑的想法是链剖线段树--但是会TLE. LCT一样无脑,但是少一个log,可以过. 正解是分类讨论, 如果t不在lca(s,f)的子树内,答案是dis(lca(s,f),f). 如果t在lca(s,f)的子树内,并且dep(lca(s,t))>dep(lca(f,t)),答案是dis(lca(s,t),f): 否则答案是dis(lca(f,t),f). #in

LA UVaLive 6862 Triples (数学+分类讨论)

题意:给定一个n和m,问你x^j + y^j = z^j 的数量有多少个,其中0 <= x <= y <= z <= m, j = 2, 3, 4, ... n. 析:是一个数学题加分类讨论.首先对 x进行分类讨论. 当 0 = x 时,只要 y = z,就行,那么就有(m+1) *  (n-1) 个,因为 y 可能从0取到m ,j 可以从2取到 n. 当 0 != x 时,那么只要一个勾股定理能构成,只要幂大于2,就一下没解,所以我们把第一种中拿出j = 2时,的特殊情况,特殊考