[bzoj4558][JLoi2016]方【容斥原理】【计数】
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=4558
【题解】
显然可以从总状态中减去不合法的状态。
对于不合法的状态,可以用容斥原理即:有一个点不合法-有两个点不合法+有三个点不合法-有四个点不合法。
对于总状态,枚举所占位置的大小,再枚举偏移程度即可统计。
对于有一个点不合法:枚举它所占的矩形的外框,即横平竖直的矩形,然后分它在四个角上(未发生偏移),在(四条边上)的方案数。
对于有两个点不合法,枚举这两个点,判断是否可行。
对于有三个点不合法,枚举两个点,判断第三个点是否合法,因为一个矩形会被枚举三遍(两条边+一条对角线)所以最后要除以3。
四个点和三个点同理,最后要除以6。
/* --------------
user Vanisher
problem bzoj-4558
----------------*/
# include <bits/stdc++.h>
# define ll long long
# define inf 0x3f3f3f3f
# define P1 1000000
# define P2 1
# define N 2010
# define Key 999983
# define P 100000007
using namespace std;
int f[Key];
struct node{
ll data,next;
}e[N];
ll read(){
ll tmp=0, fh=1; char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
return tmp*fh;
}
int place;
ll cutx[N],cuty[N],t1,t2,t3,t4,n,m,k,ans;
void join(ll x){
ll y=x%Key;
e[++place].data=x;
e[place].next=f[y];
f[y]=place;
}
ll query(ll x, ll y){
ll now=x*P1+y*P2, pp=now%Key;
for (int ed=f[pp]; ed!=0; ed=e[ed].next)
if (e[ed].data==now)
return 1;
return 0;
}
ll query1(ll x, ll y){
return min(x-1,y-1);
}
ll query2(ll x, ll y, ll nowy){
ll k=x-1, t=min(y-nowy,k), p=min(nowy-1,k);
ll cut=min(k-p,t);
return p*cut+max(((p-1)+(k-t))*((p-1)-(k-t)+1)/2,0ll);
}
void solve(ll x1, ll y1, ll x2, ll y2){
if (x1>0&&x1<=n&&x2>0&&x2<=n&&y1>0&&y1<=m&&y2>0&&y2<=m){
t2++;
ll tmp=query(x1,y1)+query(x2,y2);
t3+=tmp; t4+=(tmp==2);
}
}
void doit(ll x1, ll y1, ll x2, ll y2){
ll dx=x2-x1, dy=y2-y1;
solve(x1-dy,y1+dx,x2-dy,y2+dx);
solve(x1+dy,y1-dx,x2+dy,y2-dx);
if ((dx+dy)%2==0){
dy=(dx+dy)>>1; dx-=dy;
solve(x1+dx,y1+dy,x2-dx,y2-dy);
}
}
int main(){
n=read()+1, m=read()+1, k=read();
for (ll i=1; i<=k; i++){
cutx[i]=read()+1, cuty[i]=read()+1;
join(cutx[i]*P1+cuty[i]*P2);
}
for (ll i=2; i<=min(n,m); i++)
ans=(ans+(n-i+1)*(m-i+1)%P*(i-1))%P;
for (ll i=1; i<=k; i++){
t1=(t1+query1(cutx[i],cuty[i])+query1(n-cutx[i]+1,cuty[i]))%P;
t1=(t1+query1(cutx[i],m-cuty[i]+1)+query1(n-cutx[i]+1,m-cuty[i]+1))%P;
t1=(t1+query2(cutx[i],m,cuty[i])+query2(n-cutx[i]+1,m,cuty[i]))%P;
t1=(t1+query2(cuty[i],n,cutx[i])+query2(m-cuty[i]+1,n,cutx[i]))%P;
for (ll j=1; j<i; j++)
doit(cutx[j],cuty[j],cutx[i],cuty[i]);
}
printf("%lld\n",((ans-t1+t2-t3/3+t4/6)%P+P)%P);
return 0;
}