[AGC025-D] Choosing Points

122 篇文章 0 订阅
19 篇文章 0 订阅
Atcoder传送门

题目大意

你有一个 2N×2N 2 N × 2 N 的方格(从0开始编号), 给你两个整数 dis1,dis2 d i s 1 , d i s 2 , 要求取出 N2 N 2 个点, 使得任意两个点之间的距离不为 dis1 d i s 1 dis2 d i s 2

输入输出格式

输入格式

一行三个整数, 分别为 N,dis1,dis2 N , d i s 1 , d i s 2

输出格式

N2 N 2 行, 每行两个整数 ai,bi a i , b i ,表示取的一个点的坐标。

输入输出样例

输入样例#1
2 1 2
输出样例#1
0 0
0 2
2 0
2 2
输入样例#2
3 1 5
输出样例#2
0 0
0 2
0 4
1 1
1 3
1 5
2 0
2 2
2 4

数据范围

  • 1N300 1 ≤ N ≤ 300
  • 1dis12×105 1 ≤ d i s 1 ≤ 2 × 10 5
  • 1dis22×105 1 ≤ d i s 2 ≤ 2 × 10 5

解题分析

一道比较妙妙的构造题。

首先我们要知道勾股数的正整数分解是唯一的,即对于 dis1 d i s 1 dis2 d i s 2 都唯一存在 x1,x2,y1,y2 x 1 , x 2 , y 1 , y 2 , 使得 x21+y21=dis21, x22+y22=dis22 x 1 2 + y 1 2 = d i s 1 2 ,   x 2 2 + y 2 2 = d i s 2 2

考虑我们对原图进行两遍染色,分别处理 dis1 d i s 1 dis2 d i s 2

  • 如果 dis MOD 4=1 d i s   M O D   4 = 1 ,说明分解出来的 xy x 、 y 为一奇一偶, 所以我们染成棋盘形即可。
  • 如果 dis MOD 4=2 d i s   M O D   4 = 2 ,说明分解出来的 xy x 、 y 为两个奇数, 我们隔行染色即可。
  • 如果 dis MOD 4=0 d i s   M O D   4 = 0 , 说明分解出来的 xy x 、 y 为两个偶数, 我们可以将 xy x 、 y 都缩小一半,转换为上面两种情况处理。
  • dis MOD 4=3 d i s   M O D   4 = 3 ?老哥数学没学好吧…根本没这种情况

然后我们就可以 O(N2) O ( N 2 ) 预处理染色, O(N2) O ( N 2 ) 输出两次都没有染色的格子。 可以证明未染色的格子是不少于 N2 N 2 个的。随意输出即可。

代码如下:

#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cctype>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 610
bool vis[MX][MX];
int siz, d1, d2, bd;
void deal(R int dis)
{
    int tim = 0;//放缩倍率
    W (!(dis % 4)) dis /= 4, ++tim;
    if(dis & 1)
    {
        for (R int i = 0; i < bd; ++i)
        for (R int j = 0; j < bd; ++j)
        if((i >> tim) + (j >> tim) & 1) vis[i][j] = true;
    }
    else
    {
        for (R int i = 0; i < bd; ++i)
        for (R int j = 0; j < bd; ++j)
        if((i >> tim) & 1) vis[i][j] = true;
    }
}
int main(void)
{
    scanf("%d%d%d", &siz, &d1, &d2);
    bd = siz << 1; deal(d1), deal(d2);
    int tar = siz * siz, cnt = 0;
    for (R int i = 0; i < bd; ++i)
    for (R int j = 0; j < bd; ++j)
    {
        if(!vis[i][j]) printf("%d %d\n", i, j), cnt++;
        if(cnt == tar) return 0;
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值