AtCoder Regular Contest 089 D - Checker 思维题、点的转移、二维前缀和

D - Checker


Time limit : 2sec / Memory limit : 256MB

Score : 500 points

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:

cba927b2484fad94fb5ff7473e9aadef.png

AtCoDeer has N desires. The i-th desire is represented by xiyi 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.
  • NKxi 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

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

Sample Output 1

Copy
4

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


Sample Input 2

Copy
2 1000
0 0 B
0 1 W

Sample Output 2

Copy
2

Sample Input 3

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

Sample Output 3

Copy
4

Source

AtCoder Regular Contest 089

My Solution

题意:用k*k的黑白正方形交替填充二维坐标平面如上图,现给出n个方案(x, y, color表示坐标(x,y)的颜色为color),问最多有多少方案能够同时满足。

思维题、点的转移、二维前缀和

首先要想到把所有的点转移到平面{(0,0)~(k-1,k-1)}内。

1、按照45度向量移动不会改变颜色,

modx = x / k, mody = y / k;  x -= min(modx, mody) * k; y -= min(modx, mody) * k;

2、跳动2*k格也不会改变颜色,所以接下来

if(modx > mody) x -= (modx - mody) / 2 * 2 * k; else y -= (mody - modx) / 2 * 2 * k;

3、最后跳动k个需要改变颜色,所以

if(ch == 'W'){
    if(x / k) b[x % k][y]++;
    else if(y / k) b[x][y % k]++;
    else w[x][y]++;
}
else{
    if(x / k) w[x % k][y]++;
    else if(y / k) w[x][y % k]++;
    else b[x][y]++;
}
按照这3个步骤就可以把坐标平面上所以数据的点都转移到平面{(0,0)~(k-1,k-1)}内。

接下来要确定这个平面颜色的分配,可以用一个“十”字来划分区域。

{(0,0)~(i,j)}和{(i+1,j+1)~(k-1,k-1)}为白色,

{(0,j+1)~(i,k-1)}和{(i+1,0)~(k-1,j)}为黑色。

或者

{(0,0)~(i,j)}和{(i+1,j+1)~(k-1,k-1)}为白色,

{(0,j+1)~(i,k-1)}和{(i+1,0)~(k-1,j)}为黑色。

所以需要快速的获取一个矩形区域的数值之和,可以用二维前缀和来表示。

遍历{(0,0)~(k-1,k-1)}内所有的点,

ansb = sumb[i][j] + sumw[k-1][j] - sumw[i][j] + sumw[i][k-1] - sumw[i][j] + sumb[k-1][k-1] - sumb[i][k-1] - sumb[k-1][j] + sumb[i][j];
answ = sumw[i][j] + sumb[k-1][j] - sumb[i][j] + sumb[i][k-1] - sumb[i][j] + sumw[k-1][k-1] - sumw[i][k-1] - sumw[k-1][j] + sumw[i][j];
即可得出答案,ans = max(ans, max(ansb, answ));

时间复杂度 O(K*K)

空间复杂度 O(K*K)

#include <iostream>
#include <cstdio>
 
using namespace std;
typedef long long LL;
const int MAXN = 1e3 + 8;
 
int b[MAXN][MAXN], w[MAXN][MAXN], sumb[MAXN][MAXN], sumw[MAXN][MAXN];
 
int main()
{
    #ifdef LOCAL
    freopen("b.txt", "r", stdin);
    //freopen("b.out", "w", stdout);
    int T = 1;
    while(T--){
    #endif // LOCAL
    ios::sync_with_stdio(false); cin.tie(0);
 
    int n, k, i, j, x, y, modx, mody, ansb, answ;
    char ch;
    cin >> n >> k;
    for(i = 0; i < n; i++){
        cin >> x >> y >> ch;
        modx = x / k, mody = y / k;
        x -= min(modx, mody) * k;
        y -= min(modx, mody) * k;
        if(modx > mody){
            x -= (modx - mody) / 2 * 2 * k;
        }
        else{
            y -= (mody - modx) / 2 * 2 * k;
        }
        //cout << x << " " << y <<" " << ch << endl;
        if(ch == 'W'){
            if(x / k) b[x % k][y]++;
            else if(y / k) b[x][y % k]++;
            else w[x][y]++;
        }
        else{
            if(x / k) w[x % k][y]++;
            else if(y / k) w[x][y % k]++;
            else b[x][y]++;
        }
    }
    for(i = 0; i < k; i++){
        for(j = 0; j < k; j++){
            if(i == 0){
                if(j == 0){
                    sumb[i][j] = b[i][j];
                    sumw[i][j] = w[i][j];
                }
                else{
                    sumb[i][j] =  sumb[i][j-1] + b[i][j];
                    sumw[i][j] =  sumw[i][j-1] + w[i][j];
                }
            }
            else{
                if(j == 0){
                    sumb[i][j] =  sumb[i-1][j] + b[i][j];
                    sumw[i][j] =  sumw[i-1][j] + w[i][j];
                }
                else{
                    sumb[i][j] =  sumb[i-1][j] + sumb[i][j-1] + b[i][j] - sumb[i-1][j-1];
                    sumw[i][j] =  sumw[i-1][j] + sumw[i][j-1] + w[i][j] - sumw[i-1][j-1];
                }
            }
 
        }
    }
    //cout << k << endl;
    int ans = 0;
    for(i = 0; i < k; i++){
        for(j = 0; j < k; j++){
           // cout << ans << " " << sumb[i][j] + sumw[k-1][k-1] - sumw[i][j] << " " << sumw[i][j] + sumb[k-1][k-1] - sumb[i][j] << endl;
            ansb = sumb[i][j] + sumw[k-1][j] - sumw[i][j] + sumw[i][k-1] - sumw[i][j] + sumb[k-1][k-1] - sumb[i][k-1] - sumb[k-1][j] + sumb[i][j];
            answ = sumw[i][j] + sumb[k-1][j] - sumb[i][j] + sumb[i][k-1] - sumb[i][j] + sumw[k-1][k-1] - sumw[i][k-1] - sumw[k-1][j] + sumw[i][j];
            ans = max(ans, max(ansb, answ));
        }
    }
    cout << ans << endl;
 
 
    #ifdef LOCAL
    cout << endl;
    }
    #endif // LOCAL
    return 0;
}
 

  Thank you!

                                                                                                                                             ------from ProLights

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值