[COI2007] Sabor

添雅發表於2018-12-27

下面給出這道一臉不可做的題的鬼畜性質:
1)對於一個點來說,其歸屬狀態是確定的:走不到、A黨或B黨 。(黑白格染色)
方便起見,將包含所有不可達的點的極小矩形向外擴充套件一圈,設為矩形M。
2)矩形M的最外圈上相鄰兩點點到(0,0)的最短曼哈頓距離差值不超過1。
3)矩形M外任意正對於矩形M的點到垂直走向所正對的邊必是到(0,0)的滿足曼哈頓距離最小的路徑的一條。
4)矩形M外任意非正對於矩形M到最靠近的M的一角必是到(0,0)的滿足曼哈頓距離最小的路徑的一條。

利用這些性質就可做了。。主要是向外擴充套件一圈這兒。。

然後就是找找規律的事兒了。。

#include <bits/stdc++.h>
#define P 1000
using namespace std;
const int fx[]={1,-1,0,0};
const int fy[]={0,0,1,-1};

int B,S;
long long cnt[2];
int dis[2005][2005];
int maxx,maxy,minx,miny;
queue<int> Qx,Qy;

inline void f1(int x,int y) {
    cnt[(x+y)&1]+=1LL*((S-dis[x][y])/2)*((S-dis[x][y])/2);
    cnt[(x+y+1)&1]+=1LL*((S-dis[x][y]-1)/2)*((S-dis[x][y]-1)/2+1);
} 
inline void f2(int x,int y) {
    cnt[(x+y)&1]+=(S-dis[x][y])/2;
    cnt[(x+y+1)&1]+=(S-dis[x][y]+1)/2;
}

int main() {
    scanf("%d%d",&B,&S);
    minx=miny=maxx=maxy=P;
    for(int x,y,i=1; i<=B; ++i) {
        scanf("%d%d",&x,&y);
        x+=P,y+=P;
        dis[x][y]=-1;
        minx=min(minx,x);
        maxx=max(maxx,x);
        miny=min(miny,y);
        maxy=max(maxy,y);
    }
    S++;
    minx--,miny--;
    maxx++,maxy++;
    Qx.push(P);
    Qy.push(P);
    dis[P][P]=1;
    while(!Qx.empty()) {
        int x=Qx.front(); Qx.pop();
        int y=Qy.front(); Qy.pop();
        if((x==minx||x==maxx) && (y==miny||y==maxy)) f1(x,y);
        if((x==minx||x==maxx)) f2(x,y);
        if((y==miny||y==maxy)) f2(x,y);
        cnt[(x+y)&1]++;
        if(dis[x][y]==S) continue;
        for(int nx,ny,k=0; k<4; ++k) {
            nx=x+fx[k];
            ny=y+fy[k];
            if(nx<minx||ny<miny||nx>maxx||ny>maxy||dis[nx][ny]) continue;           
            dis[nx][ny]=dis[x][y]+1;
            Qx.push(nx);
            Qy.push(ny);
        }
    }
    printf("%lld %lld
",cnt[0],cnt[1]);
    return 0;
}