国际惯例的题面:

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


然后我们让四个点在这个正方形的边上滑动,显然这四个点的每一组位置对应一个非正放的正方形(虽然正好在四个角上的是正放的)。
于是我们可以得出总方案数为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)。

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

 #include<cstdio>
#include<algorithm>
#include<tr1/unordered_set>
using namespace std;
using namespace tr1;
typedef long long int lli;
using namespace std;
using namespace tr1;
const int maxp=2e3+1e2;
const int mod=1e8+; struct Point {
int x,y;
friend bool operator < (const Point &a,const Point &b) {
return a.x != b.x ? a.x < b.x : a.y < b.y;
}
friend Point operator - (const Point &a,const Point &b) {
return (Point){a.x-b.x,a.y-b.y};
}
friend Point operator + (const Point &a,const Point &b) {
return (Point){a.x+b.x,a.y+b.y};
}
friend Point operator * (const Point &a,const int &b) {
return (Point){a.x*b,a.y*b};
}
friend Point operator / (const Point &a,const int &b) {
return (Point){a.x/b,a.y/b};
}
inline Point swp() const {
return (Point){y,-x};
}
inline bool candiv() const {
return ( ! ( x & ) ) && ( ! ( y & ) );
}
}pt[maxp];
unordered_set<lli> st;
int n,m,t;
lli ans,ini,sig,dou,tri,qua; inline void insert(const Point &p) {
lli h = (lli) p.x * ( m + ) + p.y;
st.insert(h);
}
inline bool inside(const Point &p) {
return <= p.x && p.x <= n && <= p.y && p.y <= m;
}
inline bool legal(const Point &pa,const Point &pb) {
return inside(pa) && inside(pb);
}
inline bool have(const Point &p) {
lli h = (lli) p.x * ( m + ) + p.y;
return st.find(h) != st.end();
}
inline lli calcini(lli n,lli m) {
lli ret = , lim = min( n , m );
for(lli i=;i<=lim;i++) ret = ( ret + ( n - i + ) % mod * ( m - i + ) % mod * i % mod ) % mod;
return ret;
}
inline lli calcedge(const lli &l,const lli &r,const lli &h) {
lli t = min( l + r , h );
if( !t ) return ;
lli ret = ( t * ( t + ) >> ) % mod;
if( t > l ) ret -= ( ( t - l ) * ( t - l + ) >> ) % mod;
if( t > r ) ret -= ( ( t - r ) * ( t - r + ) >> ) % mod;
return ( ret % mod + mod ) % mod;
}
inline lli calcsingle(lli x,lli y) {
const lli a = n - x , b = m - y , c = x , d = y;
lli ret = ( calcedge(d,b,a) + calcedge(d,b,c) + calcedge(a,c,b) + calcedge(a,c,d) ) % mod;
ret -= ( min(a,b) + min(b,c) + min(c,d) + min(d,a) ) % mod;
return ( ret % mod + mod ) % mod;
}
inline lli calcdouble(const Point &a,const Point &b) {
const Point delta = (a-b).swp();
int ret = legal(a+delta,b+delta) + legal(a-delta,b-delta);
const Point mid = a + b , pa = mid + delta , pb = mid - delta;
if( pa.candiv() && pb.candiv() && legal(pa/,pb/) ) ++ret;
return ret;
}
inline lli calctriple(const Point &a,const Point &b) {
const Point delta = (a-b).swp();
int ret = ;
if( legal(a+delta,b+delta) ) ret += have(a+delta) + have(b+delta);
if( legal(a-delta,b-delta) ) ret += have(a-delta) + have(b-delta);
const Point mid = a + b , pa = mid + delta , pb = mid - delta;
if( pa.candiv() && pb.candiv() && legal(pa/,pb/) ) ret += have(pa/) + have(pb/);
return ret;
}
inline lli calcquad(const Point &a,const Point &b) {
const Point delta = (a-b).swp();
int ret = ;
if( legal(a+delta,b+delta) ) ret += ( have(a+delta) && have(b+delta) );
if( legal(a-delta,b-delta) ) ret += ( have(a-delta) && have(b-delta) );
const Point mid = a + b , pa = mid + delta , pb = mid - delta;
if( pa.candiv() && pb.candiv() && legal(pa/,pb/) ) ret += ( have(pa/) && have(pb/) );
return ret;
} int main() {
scanf("%d%d%d",&n,&m,&t);
for(int i=;i<=t;i++) scanf("%d%d",&pt[i].x,&pt[i].y) , insert(pt[i]);
ini = calcini(n,m);
for(int i=;i<=t;i++) sig += calcsingle(pt[i].x,pt[i].y);
for(int i=;i<=t;i++) for(int j=i+;j<=t;j++) {
dou += calcdouble(pt[i],pt[j]) , tri += calctriple(pt[i],pt[j]) , qua += calcquad(pt[i],pt[j]);
}
tri /= , qua /= ;
ans = ( ( ini - sig + dou - tri + qua ) % mod + mod ) % mod;
printf("%lld\n",ans);
return ;
}

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

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

    题意:从区间[L,R]中选取不多于k个数,使这些数异或和尽量小,输出最小异或和以及选取的那些数. 解法:分类讨论. 设选取k个数. 1. k=4的时候如果区间长度>=4且L是偶数,那么可以构造四 ...

  2. BZOJ-1067 降雨量 线段树+分类讨论

    这道B题,刚的不行,各种碎点及其容易忽略,受不鸟了直接 1067: [SCOI2007]降雨量 Time Limit: 1 Sec Memory Limit: 162 MB Submit: 2859 ...

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

    题意:给定一个n和m,问你x^j + y^j = z^j 的数量有多少个,其中0 <= x <= y <= z <= m, j = 2, 3, 4, ... n. 析:是一个数 ...

  4. 枚举(分类讨论):BZOJ 1177: [Apio2009]Oil

    1177: [Apio2009]Oil Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 1477  Solved: 589[Submit] Descri ...

  5. Educational Codeforces Round 63 (Rated for Div. 2) D. Beautiful Array 分类讨论连续递推dp

    题意:给出一个 数列 和一个x 可以对数列一个连续的部分 每个数乘以x  问该序列可以达到的最大连续序列和是多少 思路: 不是所有区间题目都是线段树!!!!!! 这题其实是一个很简单的dp 使用的是分 ...

  6. 【cf789B】Masha and geometric depression(分类讨论/暴力)

    B. Masha and geometric depression 题意 在黑板上写数列,首项是b,公比是q,超过l时就停止不写.给定m个数,遇到后跳过不写.问一共写多少个数,如果无穷个输出inf. ...

  7. P2331 [SCOI2005]最大子矩阵 (动规:分类讨论状态)

    题目链接:传送门 题目: 题目描述 这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大.注意:选出的k个子矩阵不能相互重叠. 输入输出格式 输入格式: 第一行为n,m,k( ...

  8. UVa 11722 Joining with Friend (几何概率 + 分类讨论)

    题意:某两个人 A,B 要在一个地点见面,然后 A 到地点的时间区间是 [t1, t2],B 到地点的时间区间是 [s1, s2],他们出现的在这两个区间的每个时刻概率是相同的,并且他们约定一个到了地 ...

  9. HDU 5203 Rikka with wood sticks 分类讨论

    题目链接: hdu:http://acm.hdu.edu.cn/showproblem.php?pid=5203 bc(chinese):http://bestcoder.hdu.edu.cn/con ...

随机推荐

  1. ViewGroup.layout(int l, int t, int r, int b)四个输入参数的含义

    ViewGroup.layout(int l, int t, int r, int b)这个方法是确定View的大小和位置的,然后将其绘制出来,里面的四个参数分别是View的四个点的坐标,他的坐标不是 ...

  2. android getWidth()和getMeasuredWidth()方法的区别

    getWidth() Return the width of the your view. Returns The width of your view, in pixels. 源代码: public ...

  3. 「Android 开发」入门笔记

    「Android 开发」入门笔记(界面编程篇) ------每日摘要------ DAY-1: 学习笔记: Android应用结构分析 界面编程与视图(View)组件 布局管理器 问题整理: Andr ...

  4. springcloud服务安全连接

    Spring Cloud可以增加HTTP Basic认证来增加服务连接的安全性. 1.加入security启动器 在maven配置文件中加入Spring Boot的security启动器. <d ...

  5. 一个查看Access数据库密码的工具

    一个可以查看Access数据库密码的工具AccessCracker.需要.net2.0环境支持. 网盘地址:https://pan.baidu.com/s/1btbsFcsKO0Enj-rjkTlz6 ...

  6. oracle数据库_实例_用户_表空间之间的关系

    基础概念:Oracle数据库.实例.用户.表空间.表之间的关系 数据库:Oracle数据库是数据的物理存储.这就包括(数据文件ORA或者DBF.控制文件.联机日志.参数文件).其实Oracle数据库的 ...

  7. (转)substring和substr以及slice和splice的用法和区别

    转载地址:https://www.cnblogs.com/echolun/p/7646025.html 那么就由一道笔试题引入吧,已知有字符串a=”get-element-by-id”,写一个func ...

  8. mysql索引 B+tree

    一.B+tree示意图 二.为什么要用索引 1.索引能极大减少存储引擎需要扫描的数据量:因为索引有序所以可以快速查找并且不用全表查找: 2.索引可以把随机IO变为顺序IO:因为B+tree在数据中保存 ...

  9. vs 加载 dll 缓慢

    https://jingyan.baidu.com/article/642c9d34e25cc2644b46f74b.html http://www.it610.com/article/2611781 ...

  10. 【论文阅读】ShuffleNet: An Extremely Efficient Convolutional Neural Network for Mobile Devices

    ShuffleNet: An Extremely Efficient Convolutional Neural Network for MobileDevices