「HNSDFZ暑期集训 测试1」「LuoguT36488」 连连看

Description


这里写图片描述

Input


这里写图片描述

Output


输出仅一行一个整数,表示当前可以消去的牌的对数

Sample Input1


3 3 3
1 3 2 2
1 1 3 3
1 2 2 1

Sample Output1


1

Hint


这里写图片描述

题解


考虑数据范围很小,我们可以做各种n方操作。

读入的同时把相应坐标标记

    flag[ i ] [ j ]=1;

套两个for循环,分别求横排上的前缀和 及竖排上的前缀和

    for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)
    ss[i][j]=ss[i-1][j]+tu[i][j],
    hs[i][j]=hs[i][j-1]+tu[i][j];

对于每组牌:

我们把一张牌分别向上下左右暴力走,走到边界或障碍就停,经过的点就标记。(画十字)

|____________|
|      O     |
|      |  O  |
|      |     |
|   O——O————O|
|      |     |
|      |     |
|  O   |     |
|______|_____|

然后把第二张牌也上下左右暴力走,同样经过则标记。如果有到被标记过的点,说明路线相交了,这对牌可消,flag=1

若未相交:

从1~n枚举横坐标j,如果这一段(< x1 , j >点到 < x2 , j >点)上的区间和为0
且< x1 , j >点和< x2 , j >点被标记过(画十字的时候经历过)的话(用前缀和O(1)查询)
则这一段没有障碍,可以连线,flag=1

从1~n枚举纵坐标i,如果< i , y1 >点到< i , y2 >上的区间和为0,则可连,flag=1

最后如果flag为1,则ans++

代码://考场代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
inline int read()//快读
{
    char ch=getchar();
    int x=0;bool s=1;
    while(ch<'0'||ch>'9'){if(ch=='-')s=0;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
    return s?x:-x;
}
int lx[5007],ly[5007],rx[5007],ry[5007];
int ss[1007][1007];
int hs[1007][1007];
bool tu[1007][1007];
bool sf[1007][1007];
int main()
{
    int n=read(),m=read(),k=read();
    for(int i=1;i<=k;++i)
    {
        lx[i]=read(),
        ly[i]=read(),
        rx[i]=read(),
        ry[i]=read();
        tu[lx[i]][ly[i]]=1;
        tu[rx[i]][ry[i]]=1;//标记
    }
    for(int i=0;i<=n+1;++i)
    tu[i][0]=tu[i][m+1]=1;
    for(int i=0;i<=m+1;++i)
    tu[0][i]=tu[n+1][i]=1;
    for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)
    ss[i][j]=ss[i-1][j]+tu[i][j],
    hs[i][j]=hs[i][j-1]+tu[i][j];//前缀和
    int ans=0;
    for(int c=1;c<=k;++c)
    {
        int flag=0;
        memset(sf,0,sizeof(sf));
        //以下一大堆为画十字
        tu[lx[c]][ly[c]]=0;
        tu[rx[c]][ry[c]]=0;//便于之后操作
        int x=lx[c],y=ly[c];
        int l,r,u,d;
        while(!tu[x][y]){sf[x--][y]=1;}
        u=x+1;
        x=lx[c]+1,y=ly[c];
        while(!tu[x][y]){sf[x++][y]=1;}
        d=x-1;
        x=lx[c],y=ly[c]-1;
        while(!tu[x][y]){sf[x][y--]=1;}
        l=y+1;
        x=lx[c],y=ly[c]+1;
        while(!tu[x][y]){sf[x][y++]=1;}
        r=y-1;
        x=rx[c],y=ry[c];
        while(!tu[x][y]){if(sf[x][y])flag++;sf[x--][y]=1;}
        u=max(u,x+1);
        x=rx[c]+1,y=ry[c];
        while(!tu[x][y]){if(sf[x][y])flag++;sf[x++][y]=1;}
        d=min(d,x-1);
        x=rx[c],y=ry[c]-1;
        while(!tu[x][y]){if(sf[x][y])flag++;sf[x][y--]=1;}
        l=max(l,y+1);
        x=rx[c],y=ry[c]+1;
        while(!tu[x][y]){if(sf[x][y])flag++;sf[x][y++]=1;}
        r=min(r,y-1);
        //画十字结束
        if(!flag)
        {
            int zx=lx[c],zy=ly[c],yx=rx[c],yy=ry[c];
            if(zx>yx)swap(zx,yx);
            if(zy>yy)swap(zy,yy);
            for(int i=u;i<=d;++i)//枚举横坐标
            if(hs[i][yy]-hs[i][zy-1]==0)flag++;
            for(int j=l;j<=r;++j)//枚举纵坐标
            if(ss[yx][j]-ss[zx-1][j]==0)flag++;
        }
        if(flag)ans++;
        tu[lx[c]][ly[c]]=1;
        tu[rx[c]][ry[c]]=1;//复原
        //cout<<flag<<endl;
    }
    cout<<ans;//强大怪!!! 
    return 0;
}

//强大怪!!!(滑稽

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值