Checker【解题报告】

探讨无限大棋盘上如何最大化满足特定染色需求的问题。需考虑降维及坐标平移技巧,通过枚举策略寻找最优解。

Checker —AtCoder - 3876

Problem Statement

AtCoDeer is thinking of painting an infinite two-dimensional grid in a checked pattern of side K. Here, a checked pattern of side K is a pattern where each square is painted black or white so that each connected component of each color is a K × K square. Below is an example of a checked pattern of side 3:
这里写图片描述
AtCoDeer has N desires. The i-th desire is represented by xi, yi and ci. If ci is B, it means that he wants to paint the square (xi,yi) black; if ci is W, he wants to paint the square (xi,yi) white. At most how many desires can he satisfy at the same time?

Constraints

1 ≤ N ≤ 105
1 ≤ K ≤ 1000
0 ≤ xi ≤ 109
0 ≤ yi ≤ 109
If i ≠ j, then (xi,yi) ≠ (xj,yj).
ci is B or W.
N, K, xi and yi are integers.

Input

Input is given from Standard Input in the following format:

N K
x1 y1 c1
x2 y2 c2
:
xN yN cN

Output

Print the maximum number of desires that can be satisfied at the same time.

Sample Input 1

4 3
0 1 W
1 2 W
5 3 B
5 4 B

Sample Output 1

4

He can satisfy all his desires by painting as shown in the example above.

Sample Input 2

2 1000
0 0 B
0 1 W

Sample Output 2

2

Sample Input 3

6 2
1 2 B
2 1 W
2 2 B
1 0 B
0 6 W
4 5 W

Sample Output 3

4

解析

啦啦啦,面对这道题我们首先要明白题意(就是因为题意理解错误,害我废了多少时间……):此题大概讲述的是,有一张无限大的’棋盘’,然后那张棋盘里包括了无数的k*k的小的方框,求一个原点,使得与规定的点的坐标尽量相同。
这道题,我们可以看出:它并不是一道算法题,那么,我们应该怎么思考呢?大体思路如下:
①我们可以看到,这道题的规模还是蛮大的,所以我们首先要做的是降维和移位,当然还有将字符转化为数字组成;
移位:

不难想到,其实移位就是平移:将每一个点的坐标%(2k),但是这不会影响结果吗?答案是不会的,因为*2k%2k都仅仅是改变了它的位置,而没有改变它的颜色。

这里写图片描述
如此,我们便可以进行平移的行动,其次,是降维,这个将会在代码中体现。而将字符转化为数字,则单独标记处理即可。
②我们可以通过移动的方式来实现、找到到底有多少个点使我们所需要的。这可以分为两个部分:一是通过移动移动’x轴’(其实是平行于x轴)或’y轴’(其实是平行于y轴)上的线段来不断的’枚举‘(如上图的黄色部分)。二是通过平移’x轴’向上,一则减,一则加。
【代码实现】

#include<cstdio>
#include<cstring>
const int MAXN = 100000;
const int MAXK = 1000;
int x[MAXN + 5], y[MAXN + 5], c[MAXN + 5];
int y1[10 * MAXK + 5];
int main() {
    int N, K, Max = 0, cnt = 0;
    scanf("%d%d",&N,&K);
    for(int i=1;i<=N;i++) {
        char ch;
        scanf("%d%d %c",&x[i],&y[i],&ch);
        x[i] = x[i] % (2*K);//降维 
        y[i] = y[i] % (2*K);
        if( ch == 'W' ) c[i] = 1;
        else c[i] = 0;
    }
    for(int i=0;i<=K;i++) 
    {
        cnt = 0;
        memset(y1,0,sizeof(y1));
        for(int j=1;j<=N;j++) 
        {
            int p = ( i<=x[j] && x[j] < i+K );
            int q = ( 0 <=y[j] && y[j] < K );
            //printf("%d %d",p,q); 
            if( p ^ q == c[j] )//通过位与来实现
            {
                cnt++;
                y1[y[j]] ++;
            }
            else 
            {
                y1[y[j]] --;
            }
        }
        for(int j=0;j<=K;j++) 
        {
            if( cnt > Max ) Max = cnt;
            if( N - cnt > Max ) Max = N - cnt;
            if( j != K )
                cnt = cnt - y1[j] - y1[K+j];
        }
    }
    printf("%d\n",Max);
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值