【模考】2018.04.29 wall

enter image description here
enter image description here

Solution

这题要发现的性质一堆一堆的
首先观察,如果不从1开始编号,从0开始编号,第 \(i\) 行第 \(j\) 列(从0开始标号)为白等价于\((i\&j)=0\)

这是因为你每进行一次迭代,相当于添加一个新的二进制位,并把两维上这位都为1的染黑。

然后对于一个矩形
enter image description here

可以发现这个矩形中的联通块个数等于下图的“L”形图案的中白色联通块个数
enter image description here

然后这个“L”形的白色联通块就是通过数橙框和粉框的联通块数,相加,如果交点处为白就减一,得到。
enter image description here

现在我们只要会算一维的情况就好了。即给定一个数x,对于每个y∈[l,r],如果(x&y)=0那么为白否则为黑,数白联通块数。
因为[l,r]的联通块数=[0,r]的-[0,l-1]的+[l和l-1都为白色],所以我们只要考虑l=0的情况就行了。

我们先特判 \(x=0\) 的情况。当 \(x≠0\) 的时候?
我们来看一个sample,x=1010011100。
开始的几个联通块起点依次是:
0000000000
0000100000
0001000000
0001100000
0100000000
0100100000
我们可以看出,每个起点是去掉 \(x\) 中的 \(1\) 和最后连续的 \(0\),类似二进制+1这样得到的,这样显然是正确的。因为显然 \(x\) 里为 \(1\) 的位置不能为 \(1\) ,并且会隔开联通块,而最后连续的 \(0\) 对联通块个数不会有影响。(感性理解)
所以
我们先把 \(x\) 末尾的 \(0\) 去掉,同时把 \(r\) 也右移。我们从高到低枚举 \(x\) 中为 \(1\) 的位,如果 \(r\) 这位也为 \(1\) ,那么 \(r\) 这格为黑色,我们应该把这位和更低的位如果 \(x\) 这位为 \(1\) 就改成 \(0\) ,否则改成 \(1\) 。接下来 \(r\) 就在某个联通块中了,我们把 \(r\)\(x\)\(0\) 的那些位相对位置不变当做一个二进制数,+1(去掉了末尾的0)输出即可。

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
int q,res,xbin[33],rbin[33],bin[33],cnt;
template<typename T> inline void read(T &x)
{
    T data=0,w=1;
    char ch=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
    if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline bool white(int x,int y)
{
    return !(x&y);
}
inline int calc(int x,int r)
{
    if(r<0)return 0;
    if(!x)return 1;
    res=0;cnt=0;
    while(!(x&1))x>>=1,r>>=1;
    for(register int i=31;i>=0;--i)xbin[i]=((x&(1<<i))?1:0),rbin[i]=((r&(1<<i))?1:0);
    for(register int i=31;i>=0;--i)
        if(!xbin[i])bin[cnt++]=rbin[i];
        else if(rbin[i])
            for(register int j=i;j>=0;--j)rbin[j]=xbin[j]^1;
    for(register int i=cnt-1;i>=0;--i)res|=(bin[i]<<(cnt-i-1));
    return res+1;
}
int main()
{
    freopen("wall.in","r",stdin);
    freopen("wall.out","w",stdout);
    read(q);
    while(q--)
    {
        int xl,yl,xr,yr;read(xl);read(yl);read(xr);read(yr);
        xl--;yl--;xr--;yr--;
        int line=calc(xl,yr)-calc(xl,yl-1)+(yl?(white(xl,yl-1)&&white(xl,yl)):0);
        int row=calc(yl,xr)-calc(yl,xl-1)+(xl?(white(xl-1,yl)&&white(xl,yl)):0);
        write(line+row-white(xl,yl),'\n');
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hongyj/p/8971485.html