hdu4698 Counting

解法:通过Xmin,Xmax和Ymin,Ymax得出的一个范围可以看成一个矩形,所以只要求出所有不包含平面内的点的矩形,然后总数减去这些矩形数即可。

           对于一个空白矩形a*b,他的子矩形个数为a(a+1)/2* b*(b+1)/2.

           要求出所有不符合条件的矩形只需要枚举所有下边界,然后求出所有以这个下边界出发的矩形即可。

#include<stdio.h>
#include<set>
#include<algorithm>
#define LL long long
using namespace std;
const int mod=1000000000+7;
struct node
{
    int x,y,id;
    bool operator <(const node &item)const{
        return x==item.x?(y<item.y):x<item.x;
    }
}f[2222],ff[2222];
int n,m,pre[2222],nxt[2222];
bool cmp(node a,node b)
{
    return a.y==b.y?(a.x<b.x):a.y<b.y;
}
set<node>mm;

LL calcu(int s)
{
    LL ans=(LL)s*(s+1)/2;
    if(ans>=mod)ans%=mod;
    return ans;
}
LL modstyle(LL s)
{
    if(s>=mod)s%=mod;
    return s;
}
int main()
{
    int k,i,j;
    while(scanf("%d%d%d",&n,&m,&k)!=-1)
    {
        for(i=0;i<k;i++)scanf("%d%d",&f[i].x,&f[i].y);
        sort(f,f+k);
        for(i=1,j=1;i<k;i++)
        {
            if(f[i].x==f[i-1].x&&f[i].y==f[i-1].y)continue;
            f[j++]=f[i];
        }
        k=j;
        mm.clear();
        for(i=0;i<k;i++)
        {
            f[i].id=i;ff[i]=f[i];
            if(i==0||f[i].x!=f[i-1].x)mm.insert(f[i]);
        }
        sort(f,f+k,cmp);
        for(i=0;i<k;i++)
        {
            pre[i]=nxt[i]=-1;
            for(j=0;j<i;j++)
            {
                if(f[j].x<f[i].x&&(pre[i]==-1||f[ pre[i] ].x<f[j].x))pre[i]=j;
                if(f[j].x>f[i].x&&(nxt[i]==-1||f[ nxt[i] ].x>f[j].x))nxt[i]=j;
            }
        }
        set<node>::iterator it;
        int ed,h,st=1,l,r,id,s1,s2;
        LL ans=0;
        for(i=0;i<k;i++)
        {
            ed=f[i].y-st;
            l=0;r=n+1;
            if(i&&f[i-1].y==f[i].y)l=f[i].x;
            if(i+1<k&&f[i+1].y==f[i].y)r=f[i+1].x;
            if(i==0||f[i].y!=f[i-1].y)ans+=calcu(n)*calcu(ed);
            ans=modstyle(ans);
            ed++;
            for(j=i+1;j<k;j++)
            {
                if(f[j].x<=l||f[j].x>=r)continue;
                id=f[j].id;
                if(id&&ff[id-1].x==f[j].x&&(ff[id-1].y>f[i].y||ff[id-1].y==f[i].y&&ff[id-1].x>=f[i].x))continue;
                if(nxt[j]==-1){
                    s2=r-1;h=0;
                }
                else{
                    s2=f[ nxt[j] ].x-1;
                    h=f[ nxt[j] ].y;
                }
                if(pre[j]==-1){
                    s1=0;
                }
                else{
                    s1=f[ pre[j] ].x;
                    h=max(h,f[ pre[j] ].y);
                }
                s2=s2-s1;
                h=f[j].y-h;
                ans+=calcu(s2)*modstyle((LL)h*ed);
                ans=modstyle(ans);
            }
            node p;
            int lastx=l+1,lasty=0;
            for(it=mm.begin();it!=mm.end();it++)
            {
                p=*it;
                if(p.x<=l)continue;
                if(p.x>=r)break;
                h=max(lasty,p.y);
                h=m-h+1;
                s2=p.x-lastx;
                ans+=calcu(s2)*modstyle((LL)h*ed);
                ans=modstyle(ans);
                lastx=p.x+1;lasty=p.y;
            }
            it--;
            p=*it;
            h=m-p.y+1;
            s2=r-p.x-1;
            ans+=calcu(s2)*modstyle((LL)h*ed);
            ans=modstyle(ans);

            if(i+1<k&&f[i+1].y!=f[i].y)st=f[i].y+1;

            mm.erase(f[i]);
            id=f[i].id;
            if(id+1<k&&ff[id+1].x==f[i].x)mm.insert(ff[id+1]);

            int left=-1,right=-1,flag=0;
            for(j=i+1;j<k;j++)
            {
                if(f[j].x<f[i].x)
                {
                    if(nxt[j]==i)nxt[j]=right;
                    if(left==-1||f[left].x<f[j].x)left=j;
                }
                else if(f[j].x>f[i].x)
                {
                    if(pre[j]==i)pre[j]=left;
                    if(right==-1||f[right].x>f[j].x)right=j;
                }
                else if(!flag)
                {
                    left=right=j;
                    flag=1;
                }
            }
        }
        ans+=calcu(n)*calcu(m-f[k-1].y);
        ans=calcu(n)*calcu(m)-ans;
        ans=(ans%mod+mod)%mod;
        printf("%I64d\n",ans);
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值