BZOJ 4558 [JLoi2016] 方
2017-06-02 20:16
483 查看
Description
上帝说,不要圆,要方,于是便有了这道题。由于我们应该方,而且最好能够尽量方,所以上帝派我们来找正方形上帝把我们派到了一个有N行M列的方格图上,图上一共有(N+1)×(M+1)个格点,我们需要做的就是找出这些格点形
成了多少个正方形(换句话说,正方形的四个顶点都是格点)。但是这个问题对于我们来说太难了,因为点数太多
了,所以上帝删掉了这(N+1)×(M+1)中的K个点。既然点变少了,问题也就变简单了,那么这个时候这些格点组成
了多少个正方形呢?
Input
第一行三个整数 N, M, K, 代表棋盘的行数、 列数和不能选取的顶点个数。 保证 N, M >= 1, K <=(N + 1) ×(M + 1)。约定每行的格点从上到下依次用整数 0 到 N 编号,每列的格点依次用 0到 M 编号。接下来 K 行,每
行两个整数 x,y 代表第 x 行第 y 列的格点被删掉了。保证 0 <=x <=N<=10^6, 0 <=y<=M<=10^6,K<=2*1000且不
会出现重复的格点。
Output
仅一行一个正整数, 代表正方形个数对 100000007( 10^8 + 7) 取模之后的值Sample Input
2 2 41 0
1 2
0 1
2 1
Sample Output
1HINT
Source
~~~~~~~~~~~~~~~~~~~~~~~~~~容斥原理~
答案可以看成是所有正方形数-至少有1个坏点+至少有2个坏点-至少有3个坏点+至少有4个坏点。
所有正方形数:斜的正方形可以补全为正的正方形,所以一个边长为n的正方形框架里面一共有n个正方形。
至少有1个坏点:分为坏点在正方形四角上和四边上(四边上即在斜的正方形的角上),分别计算。
剩下的情况:枚举两个坏点,就可以确定出三个正方形(注意两点是对角线时要判断是不是整点正方形),判断其余两个点是不是坏点,注意这里所有枚举都是[至少有]。
取模好奇怪啊……把(ans+(m-i+1)*(n-i+1)%modd*i%modd)%modd里面i后面的%modd去掉,就从WA到A了QAQ
最后注意x3/3,x4/6(重复枚举)。
(写代码的时候重复用了变量a,居然没有报错导致WA了好久,以后要注意!)
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<map> using namespace std; #define ll long long const ll modd=1e8+7; int n,m,k,ni3,ni6; ll ans,x1,x2,x3,x4; struct node{ int x,y; }a[2001]; map<node,bool> id; bool operator < (node u,node v) { return u.x==v.x ? u.y<v.y:u.x<v.x; } int read() { int x=0,f=1;char ch=getchar(); while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();} while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return x*f; } bool kk(node u) { return u.x>=0 && u.x<=n && u.y>=0 && u.y<=m; } void add(node a,node b) { map<node,bool>::iterator a1,b1; a1=id.find(a);b1=id.find(b);x2++; if(a1!=id.end() || b1!=id.end()) x3++; if(a1!=id.end() && b1!=id.end()) x4++; } void cal(int u,int v) { int x1=a[u].x,x2=a[v].x,y1=a[u].y,y2=a[v].y,k1,k2; node a1,b1; a1=(node){x1+y1-y2,y1+x2-x1}; b1=(node){x2+y1-y2,y2+x2-x1}; if(kk(a1) && kk(b1)) add(a1,b1); a1=(node){2*x1-a1.x,2*y1-a1.y}; b1=(node){2*x2-b1.x,2*y2-b1.y}; if(kk(a1) && kk(b1)) add(a1,b1); if((abs(x1-x2)+abs(y1-y2))&1) return; k1=(x1-y1-x2+y2)/2;k2=(x1+y1-x2-y2)/2; a1=(node){x1-k1,y1-k2}; b1=(node){x2+k1,y2+k2}; if(kk(a1) && kk(b1)) add(a1,b1); } ll num(int u,int v,int k) { ll z=min(u+v,k),now; if(!z) return 0; now=(z+3)*z/2; if(z>u) now-=(z-u)*(z-u+1)/2; if(z>v) now-=(z-v)*(z-v+1)/2; return now; } ll cal0(node u) { int x=u.x,y=u.y,a=x,b=n-x,c=y,d=m-y; return (num(a,b,c)+num(a,b,d)+num(c,d,a)+num(c,d,b)-min(a,c)-min(a,d)-min(b,c)-min(b,d)+modd)%modd; } int main() { n=read();m=read();k=read(); for(int i=min(n,m);i;i--) ans=(ans+(m-i+1)*(n-i+1)%modd*i)%modd; for(int i=1;i<=k;i++) { a[i].x=read();a[i].y=read();id[a[i]]=1; ans=(ans-cal0(a[i]))%modd; } for(int i=1;i<k;i++) for(int j=i+1;j<=k;j++) cal(i,j); ans=(ans+x2+x4/6-x3/3+modd)%modd; printf("%lld\n",ans); return 0; }
相关文章推荐
- bzoj4558 [JLoi2016]方
- BZOJ4558: [JLoi2016]方
- 【JLOI2016】bzoj4558 方
- [BZOJ4558][JLoi2016]方(数学相关+容斥原理)
- [BZOJ4558] [JLoi2016]方
- 【BZOJ 4558】 4558: [JLoi2016]方 (计数、容斥原理)
- BZOJ 4558|JLOI 2016|SHOI 2016|方|容斥原理
- bzoj4558[JLoi2016]方 容斥+count
- Bzoj4558 [JLoi2016]方
- BZOJ4558 [JLoi2016]方
- bzoj 4558: [JLoi2016]方 数学&计数
- [bzoj4558][JLoi2016]方【容斥原理】【计数】
- bzoj千题计划281:bzoj4558: [JLoi2016]方
- 【BZOJ】4558: [JLoi2016]方
- BZOJ 4557: [JLoi2016]侦察守卫 树形dp
- bzoj 4561: [JLoi2016]圆的异或并(扫描线+set)
- bzoj 4557 [JLoi2016]侦察守卫
- ●BZOJ 4559 [JLoi2016]成绩比较(容斥)
- bzoj 4559: [JLoi2016]成绩比较 dp+拉格朗日插值
- bzoj4561: [JLoi2016]圆的异或并 圆的扫描线