JLOI2016 方

bzoj4558ios

真是一道很是excited的題目啊…JLOI有毒函數

題目大意:給一個(N+1)*(M+1)的網格圖,格點座標爲(0~N,0~M),如今挖去了K個點,求剩下多少個正方形(須要注意的是正方形能夠是斜着的,多斜均可以)spa

N,M<=10^6,K<=2*10^3。3d

首先咱們發現有一個很是感人的K=0部分分…code

咱們考慮K=0怎麼作。blog

對於一個形如這樣的正方形,咱們叫它(a,b)正方形好了。ci

image

咱們能夠很容易地發現一個(a,b)正方形實際上要佔下(a+b)*(a+b)這麼大一塊網格。get

而後咱們考慮a+b的大小,這樣a就是[0,a+b]這麼大,這樣就能夠獲得一個答案。it

代碼以下:io

image

如今咱們發現,有了這些障礙物,咱們只要能求出總共的正方形個數、通過一個障礙點的正方形個數、通過兩個障礙點的正方形個數、通過三個點的、通過四個點的便可。

通過三個和通過四個直接二分查找一下顯然是trivial的,通過兩個點的要考慮是做爲邊往兩側延伸和做爲對角線的狀況,也比較trivial。

總共的正方形個數咱們已經求出來了,如今咱們就要考慮通過某一個障礙點的正方形個數。

對於一個點和它相關的只有四個屬性,u,d,l,r對吧。

image

首先咱們考慮直的正方形,即(0,x)或(x,0)正方形,由於這類正方形容易被重複統計。

image

容易發現這類正方形個數爲min(u,l)+min(u,r)+min(l,d)+min(d,r)。

其它的正方形顯然都是在四個象限中某兩個相鄰象限的。

image

爲了簡化起見,咱們先考慮l,r,d這一象限的。

仍是同樣,設正方形爲(a,b)正方形,咱們枚舉a+b,假設a+b=c。

由於正方形不是直的,因此a,b≠0。

如今咱們考慮求出a的取值範圍。

容易發現a<=r,a<=c-1,a>=1,a>=c-l(因爲b<=l)。

那麼咱們能夠列出一個形如這樣的式子來計算:

image

這樣顯然不夠優秀,咱們能夠人工分類討論一下…

額其實注意到當r=c-1時c=r+1,當c-l=1時c=l+1,那麼min和max的兩個「分界點」是l+1和r+1,在分界點中間顯然都是一些一次函數,那麼就都是等差數列,因而咱們就能夠避免人工分類討論了。

image

有了這個函數calc(l,r,d),那麼calc(u,d,l,r)顯然就等於

image

一些奇怪的細節詳見代碼…

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <math.h>
using namespace std;
typedef long long ll;
#define MOD 100000007
ll calc(ll l,ll r,ll d)
{
    if(!l||!r||!d) return 0;
    ll ans=0;
    ll upp=min(l+r,d);
    ll ps[3]={l+1,r+1,upp};
    sort(ps,ps+3);
    ll cl=1;
    for(int i=0;i<3;i++)
    {
        ll cr=ps[i];
        if(cr>upp) break;
        if(cr<2||cl==cr) continue;
        ++cl;
        ll vl=min(r,cl-1)-max(cl-l,1LL)+1;
        ll vr=min(r,cr-1)-max(cr-l,1LL)+1;
        ans+=(vl+vr)*(cr-cl+1)/2;
        ans%=MOD;
        cl=cr;
    }
    return ans;
}
ll calc(ll u,ll d,ll l,ll r)
{
    return calc(u,d,l)+calc(u,d,r)+calc(l,r,u)+calc(l,r,d)
          +min(u,r)+min(u,l)+min(d,l)+min(d,r);
}
typedef pair<ll,ll> pll;
pll ps[233333];
#define X first
#define Y second
ll n,m,k,ans=0;
bool ok(pll a)
{
    return a.X>=0&&a.X<n&&a.Y>=0&&a.Y<m;
}
ll tointt(double x)
{
    if(fabs(x-ll(x+0.5))<1e-5) return x+0.5;
    return -1;
}
double chk(double x,double y)
{
    ll xx=tointt(x),yy=tointt(y);
    if(xx>=0&&xx<n&&yy>=0&&yy<m) return 1;
    return 0;
}
int main()
{
    cin>>n>>m>>k; ++n; ++m;
    ll cnt3=0,cnt4=0;
    for(ll g=1;g<=n&&g<=m;g++) ans+=(n-g)%MOD*(m-g)%MOD*g%MOD, ans%=MOD;
    for(int i=1;i<=k;i++)
    {
        ll x,y;
        scanf("%lld%lld",&x,&y);
        ans-=calc(x,n-1-x,y,m-1-y);
        ans%=MOD;
        ps[i]=pll(x,y);
    }
    sort(ps+1,ps+1+k);
    for(int i=1;i<=k;i++)
    {
        for(int j=i+1;j<=k;j++)
        {
            do{
                double mx=(ps[i].X+ps[j].X)/2.0,my=(ps[i].Y+ps[j].Y)/2.0;
                double dx=ps[i].X-mx,dy=ps[i].Y-my;
                if(chk(mx-dy,my+dx)&&chk(mx+dy,my-dx)) ans++;
            }while(0);
            for(int p=-1;p<=1;p+=2)
            {
                ll dx=ps[j].X-ps[i].X,dy=ps[j].Y-ps[i].Y;
                pll n1=pll(ps[j].X-dy*p,ps[j].Y+dx*p);
                pll n2=pll(ps[i].X-dy*p,ps[i].Y+dx*p);
                if(ok(n1)&&ok(n2));else continue;
                ans++;
                int cp=0;
                if(binary_search(ps+1,ps+1+k,n1)) ++cp;
                if(binary_search(ps+1,ps+1+k,n2)) ++cp;
                if(cp==1) cnt3++;
                else if(cp==2) cnt3++, cnt4++;
            }
        }
    }
    ans-=cnt3/2; ans-=cnt4/4;
    printf("%d\n",int(((ans%MOD)+MOD)%MOD));
}
相關文章
相關標籤/搜索