[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;
}

转载于:https://www.cnblogs.com/Vanisher/p/9135992.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值