[BZOJ4558][JLoi2016]方(数学相关+容斥原理)
2017-03-24 22:10
405 查看
题目描述
传送门题解
这题有毒啊…首先容斥一下
答案=整个网格内的正方形数-至少有1个点是不合法点的正方形数+恰好有2个点是不合法点的正方形数*2+恰好有3个点是不合法点的正方形数-恰好有4个点是不合法点的正方形数
整个网格内的正方形数看似不好算,因为有正着斜着的正方形,但是可以发现每一个正方形都是由其外接正方形决定的,也就是可以枚举外接正方形的边长,一个边长为a的外接正方形可以确定出来a个正方形
恰好有2个、3个、4个点是不合法点的正方形数可以通过枚举两个不合法点,然后将这两个点当做某一条边的端点、对角线的端点确定出来3个正方形,然后计算就行了。得知了两个点的坐标是可以通过横纵坐标的增减量计算出来剩下两个点的左坐标。
关键是至少有一个点是不合法点的正方形数不大好算。首先可以枚举一个不合法点,但是一个顶点是这个点 的正方形数怎么算呢?
经过n次失败的尝试之后终于看了题解,贴上一个感觉还挺好的讲解:
http://blog.csdn.net/huanghongxun/article/details/51267460
代码
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> using namespace std; #define Mod 100000007 #define LL long long #define N 2005 #define gets(x,y) ((LL)((x)+(y))*((y)-(x)+1)>>1) struct data { int x,y; bool operator < (const data &a) const { return x<a.x||(x==a.x&&y<a.y); } }p ; int n,m,k,tot[5]; LL ans; LL calc(int l,int r,int h) { LL ans=0; int z=min(l+r,h); if (!z) return 0; ans=(LL)z*(z+3)/2; if (z>l) ans-=(LL)(z-l)*(z-l+1)/2; if (z>r) ans-=(LL)(z-r)*(z-r+1)/2; return ans%Mod; } LL calc_one() { LL ans=0; for (int i=1;i<=k;++i) { int x=p[i].x,y=p[i].y; ans+=calc(x-1,n-x,y-1); ans+=calc(x-1,n-x,m-y); ans+=calc(y-1,m-y,x-1); ans+=calc(y-1,m-y,n-x); ans=(ans-min(x-1,y-1)-min(x-1,m-y)-min(n-x,y-1)-min(n-x,m-y))%Mod; } return ans; } int findl(int x) { int l=1,r=k,mid,ans=-1; while (l<=r) { mid=(l+r)>>1; if (p[mid].x==x) ans=mid,r=mid-1; else if (p[mid].x<x) l=mid+1; else r=mid-1; } return ans; } int findr(int x) { int l=1,r=k,mid,ans=-1; while (l<=r) { mid=(l+r)>>1; if (p[mid].x==x) ans=mid,l=mid+1; else if (p[mid].x<x) l=mid+1; else r=mid-1; } return ans; } int find(int l,int r,int x) { int mid,ans=0; while (l<=r) { mid=(l+r)>>1; if (p[mid].y==x) return mid; else if (p[mid].y>x) r=mid-1; else l=mid+1; } return ans; } bool check(data now) { int l=findl(now.x); int r=findr(now.x); if (l==-1||r==-1) return 0; if (find(l,r,now.y)) return 1; else return 0; } LL calc_ttf() { for (int i=1;i<=k;++i) for (int j=i+1;j<=k;++j) { int a=p[i].x,b=p[i].y,c=p[j].x,d=p[j].y,x,y,r,s,t,u,f,g; int cnt; data now; x=c-a,y=d-b; r=a+y,s=b-x,t=c+y,u=d-x; if (r>0&&r<=n&&s>0&&s<=m&&t>0&&t<=n&&u>0&&u<=m) { cnt=2; now.x=r,now.y=s; if (check(now)) ++cnt; now.x=t,now.y=u; if (check(now)) ++cnt; ++tot[cnt]; if (tot[cnt]==Mod) tot[cnt]=0; } x=c-a,y=d-b; r=a-y,s=b+x,t=c-y,u=d+x; if (r>0&&r<=n&&s>0&&s<=m&&t>0&&t<=n&&u>0&&u<=m) { cnt=2; now.x=r,now.y=s; if (check(now)) ++cnt; now.x=t,now.y=u; if (check(now)) ++cnt; ++tot[cnt]; if (tot[cnt]==Mod) tot[cnt]=0; } x=c-a;y=d-b; if ((y-x)%2!=0) continue; g=(y-x)/2; f=g-y; r=c+f,s=d-g,t=c+g,u=d+f; if (r>0&&r<=n&&s>0&&s<=m&&t>0&&t<=n&&u>0&&u<=m) { cnt=2; now.x=r,now.y=s; if (check(now)) ++cnt; now.x=t,now.y=u; if (check(now)) ++cnt; ++tot[cnt]; if (tot[cnt]==Mod) tot[cnt]=0; } } tot[3]/=3,tot[4]/=6; return (tot[2]+tot[3]*2+tot[4]*3)%Mod; } int main() { scanf("%d%d%d",&n,&m,&k);++n,++m; for (int i=1;i<=k;++i) { scanf("%d%d",&p[i].x,&p[i].y); ++p[i].x,++p[i].y; } sort(p+1,p+k+1); for (int i=2;i<=min(n,m);++i) { ans+=(LL)(n-i+1)*(m-i+1)%Mod*(i-1)%Mod; ans%=Mod; } ans-=calc_one(); ans+=calc_ttf(); ans=(ans%Mod+Mod)%Mod; printf("%lld\n",ans); }
相关文章推荐
- 【BZOJ 4558】 4558: [JLoi2016]方 (计数、容斥原理)
- BZOJ 4558|JLOI 2016|SHOI 2016|方|容斥原理
- bzoj 4558: [JLoi2016]方 数学&计数
- [bzoj4558][JLoi2016]方【容斥原理】【计数】
- bzoj4558[JLoi2016]方 容斥+count
- [BZOJ4542][Hnoi2016]大数(莫队+数学相关)
- bzoj千题计划281:bzoj4558: [JLoi2016]方
- BZOJ4558: [JLoi2016]方
- [BZOJ4558] [JLoi2016]方
- [JLoi 2016] bzoj4559 成绩比较 [容斥原理]
- 【BZOJ】4558: [JLoi2016]方
- BZOJ 4558 [JLoi2016] 方
- BZOJ4558 [JLoi2016]方
- 【JLOI2016】bzoj4558 方
- Bzoj4558 [JLoi2016]方
- bzoj4558 [JLoi2016]方
- [BZOJbegin][NOIP十连测第九场]小P的单调数列(数学相关+dp+bit)
- bzoj千题计划270:bzoj4559: [JLoi2016]成绩比较(拉格朗日插值)
- BZOJ1853 [Scoi2010]幸运数字 [容斥原理]【组合数学】
- 【BZOJ 4557】【JLOI 2016】侦查守卫