bzoj 4558: [JLoi2016]方 数学&计数

来源:互联网 发布:中国对外文化贸易数据 编辑:程序博客网 时间:2024/05/23 02:01

       首先通过容斥转化为求:所有正方形-至少有1个坏点的正方形+至少有2个的-至少有3个的+有4个的。

       所有正方形:显然一个正方形不管是斜的还是正的,它所占的网格中的空间一定是一个正的正方形,不妨称为该正方形的框架。于是我们可以枚举这个正方形的框架的边长,然后枚举偏离多少格即可。

       至少有1个坏点:我们枚举坏点,然后同样枚举包含这个坏点的正方形的框架,那么这个坏点在框架上的位置,共两个大类(在边上不在角上和在角上),八个小类(四条边四个角)分别统计一下即可。

       至少有2个坏点:枚举2个坏点,此时正方形就是固定的共三种形态,算出三种形态的四个角统计即可。可以顺便把含3,4个坏点的一起统计。

       最后注意一个正方形可能被多次统计。

AC代码如下:

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#define ll long long#define mod 100000007#define gets(x,y) ((ll)((x)+(y))*((y)-(x)+1)>>1)#define N 2005using namespace std;int m,n,cnt,ans,t1,t2,t3,t4,a[N],b[N];struct hsh_node{int tot,fst[2010527],px[N],py[N],nxt[N];void ins(int x,int y){int z=(x*97+y)%2010527;px[++tot]=x; py[tot]=y; nxt[tot]=fst[z]; fst[z]=tot;}int find(int x,int y){int z=(x*97+y)%2010527,p;for (p=fst[z]; p; p=nxt[p])if (px[p]==x && py[p]==y) return 1;return 0;}}hsh;bool inmp(int x,int y){ return x>=0 && x<=m && y>=0 && y<=n; }void calc(int x,int y,int z){if (!x || !y || z<2) return;z=min(z,x+y);x=min(x,z-1); y=min(y,z-1);t1=(t1+(ll)(z-y)*y)%mod;t1=(t1+gets(z-x,y-1))%mod;}void updt(int u1,int v1,int u2,int v2){if (inmp(u1,v1) && inmp(u2,v2)){int tmp=hsh.find(u1,v1)+hsh.find(u2,v2);t2++; t3+=tmp; if (tmp>1) t4++;}}void solve(int x1,int y1,int x2,int y2){int dx=x2-x1,dy=y2-y1;updt(x1+dy,y1-dx,x2+dy,y2-dx);updt(x1-dy,y1+dx,x2-dy,y2+dx);if (abs(dx+dy)&1) return;dy=(dx+dy)>>1; dx-=dy;updt(x1+dx,y1+dy,x2-dx,y2-dy);}int main(){scanf("%d%d%d",&m,&n,&cnt); int i,j;for (i=1; i<=cnt; i++){scanf("%d%d",&a[i],&b[i]);hsh.ins(a[i],b[i]);}for (i=1; i<=m && i<=n; i++)ans=(ans+(ll)i*(m-i+1)%mod*(n-i+1))%mod;for (i=1; i<=cnt; i++){calc(a[i],m-a[i],b[i]); calc(a[i],m-a[i],n-b[i]);calc(b[i],n-b[i],a[i]); calc(b[i],n-b[i],m-a[i]);t1=(t1+min(a[i],b[i])+min(a[i],n-b[i])+min(m-a[i],b[i])+min(m-a[i],n-b[i]))%mod;for (j=1; j<i; j++) solve(a[i],b[i],a[j],b[j]);}printf("%d\n",(ans-t1+t2-t3/3+t4/6+mod)%mod);return 0;}


by lych

2016.5.23

0 0