【2020年牛客暑假第三场】D题Points Construction Problem

【2020年牛客暑假第三场】D题Points Construction Problem--数学、构造

题目链接:https://ac.nowcoder.com/acm/contest/5668/D

题目描述
Imagine you have an infinite 2D plane with Cartesian coordinate system. Initially, all the integral points are painted as white. You are given two integers n, and m. Please paint exactly n integral points to black such that there are exactly m pairs of points which satisfy the following conditions:

  1. The two points are colored by different colors.

  2. the two points are adjacent. We call two integral points ( x 1 , y 1 ) a n d ( x 2 , y 2 ) (x1,y1)and(x2,y2) (x1,y1)and(x2,y2)being adjacent if and only if ∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ = 1 |x1-x2|+|y1-y2|=1 x1x2+y1y2=1(|v| means the absolute value of v.)

  3. The x and y coordinates of all black points are in the range [ − 1 0 9 , 1 0 9 ] [-10^9,10^9] [109,109]

输入描述

The first line contains one integer t ( 1 ≤ t ≤ 1 0 3 ) (1\leq t\leq 10^3) (1t103)— the number of test cases.
The only line of each test case contains two integers n and m ( 1 ≤ n ≤ 50 , 1 ≤ m ≤ 200 ) (1\leq n \leq 50, 1\leq m \leq 200) (1n50,1m200)

输出描述

For each test, if there exists at least one configuration to choose n points to satisfy the conditions given by statement, you should print n+1 line for this test. The first line contains one string “Yes”. And the following n lines contain the coordinator of these n points which is colored as black. If there are no solution, please print one line containing only one string “No”.

扫描二维码关注公众号,回复: 11869911 查看本文章

输入
6 6 6
5 5 5 20 20 20
1 1 1 2 2 2
1 1 1 3 3 3
1 1 1 4 4 4
1 1 1 5 5 5
3 3 3 8 8 8

输出
Y e s Yes Yes
1 1 1 1 1 1
2 2 2 2 2 2
3 3 3 3 3 3
4 4 4 4 4 4
5 5 5 5 5 5
N o No No
N o No No
Y e s Yes Yes
1 1 1 1 1 1
N o No No
Y e s Yes Yes
1 1 1 1 1 1
1 1 1 2 2 2
2 2 2 1 1 1

题意

给你n个黑点,m个点对,问是否存在一种情况使其满足,若满足则输出Yes并输出每个黑点的坐标,否则输出No。

思路

一个黑点最多与4个白点组成点对,2个相邻的黑点组成6和黑点,4个黑点组成8个黑点,所以黑点越集中(方形)点对越少,最少有2(a+b),a和b分别是长方形的长和宽,黑点越分散,点对越多,最多有4n个点对。并且加黑点之后总点对会 0 、 + 2 、 − 2 、 + 4 、 − 4 0、+2、-2、+4、-4 0+22+44五种操作,所以m不可能为奇数。

然后我们需要先找出n个黑点组成点对的上下界。
上界: 4 ∗ n 4*n 4n
下界: 2 ∗ ( a + b ) 2*(a+b) 2(a+b)

由下界可知,令 x = ( 2 ∗ ( a + b ) ) / 2 − 1 x=(2*(a+b))/2-1 x=(2(a+b))/21,所以这 x x x个黑点组成“ L L L”的形状,这个“L”的形状长为 a a a,宽为 b b b,这就知道为什么要减一了,因为“ L L L”的折点会被算上两次。所以m个点对最少由 x x x个黑点组成,最多由 a ∗ b a*b ab个黑点组成。则当 x > m x>m x>m时,则将 L L L中的 x − m x-m xm个黑点移走并使得每个黑点组成4个点对,那么总点数 x + = 2 x += 2 x+=2,直到总点对等于 m m m x < m x<m x<m时,然后将黑点依次加入到“ L L L”中(最多就是一个方形,所以还要判断一下,如果 a ∗ b < n a*b<n ab<n,那么就不符合,输出 N o No No),那么每加一个黑点总点数 m m − = 2 mm -= 2 mm=2,直到 x = n x=n x=n

所有有以下几种情况:

  • m < 4 ∣ ∣ m 为 奇 数 ∣ ∣ m > 4 ∗ n 时 , 无 解 m< 4 || m为奇数 || m>4*n时,无解 m<4mm>4n
  • m = 4 ∗ n 正 好 匹 配 , 有 解 m = 4*n正好匹配,有解 m=4n
  • 若 n > a ∗ b , 无 解 若n>a*b,无解 n>ab
  • 判 断 x 和 m 的 大 小 关 系 。 x > m 时 , 加 孤 立 黑 点 ( 有 四 个 点 对 ) , x < m 时 , 往 “ L ” 里 加 黑 点 , 并 且 加 在 和 两 个 黑 点 相 邻 的 位 置 , 有 解 判断x和m的大小关系。x>m时,加孤立黑点(有四个点对),x<m时,往“L”里加黑点,并且加在和两个黑点相邻的位置,有解 xmx>mx<mL

Code

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<int, int> pdd;

#define INF 0x7f7f7f
#define mem(a,b) memset(a , b , sizeof(a))
#define FOR(i, x, n) for(int i = x;i <= n; i++)
// const ll mod = 1e9 + 7;
const int maxn = 5e4 + 10;
// const double eps = 1e-6;

struct Point {
    
    
    int x, y;
}p[505];

int n, m, tot, t;

void solve()
{
    
    
    tot = 0;
    cin >> n >> m;
    if (m & 1 || m > 4 * n || m < 4) // 无解
    {
    
    
        cout << "No" << endl;
        return;
    }
    if (n == 1)
    {
    
    
        if (m == 4)
        {
    
    
            cout << "Yes" << endl;
            cout << "1 1" << endl;
            return ; 
        }
        else
        {
    
    
            cout << "No" << endl;
            return;
        }
    }
    if (m == n * 4) // 正好匹配
    {
    
    
        cout << "Yes" << endl;
        for (int i = 1; i <= n; i++)
        {
    
    
            cout << i * 3 + 1234 << " " << i * 3 + 1234 << endl;
        }
        return;
    }
    int x = 0, y = 0, z = 0;
    x = m / 2 - 1; 
    if (x > n) // 需要从n中拿出x-n个使他们每个点对都是4,这样每拿走一个总点对就会+2
    {
    
    
        for (int i = 1; i <= x - n; i++)
        {
    
    
            p[i].x = i * 3 + 1234; 
            p[i].y = i * 3 + 1234;
        }
        tot = x - n;
        for (int i = tot + 1; i <= n; i++)
        {
    
    
            p[i].x = 1;
            p[i].y = i;
        }
        tot = n;
    }
    else // 说明需要往“L”阵加点,每加一个点就会使总点对-2
    {
    
    
        z = x;
        x = (z + 1) / 2;
        y = (z + 1) - x;
        if (x * y < n) // x*y的全部点数小于n,那么就是No
        {
    
    
            cout << "No" << endl;
            return;
        }
        for (int i = 1; i <= x; i++)
        {
    
    
            tot++;
            p[tot].x = i;
            p[tot].y = 1;
        }
        for (int i = 2; i <= y; i++)
        {
    
    
            tot++;
            p[tot].x = 1;
            p[tot].y = i;
        }
        for (int i = 2; i <= x; i++) // 往“L”里加点
        {
    
    
            for (int j = 2; j <= y; j++)
            {
    
    
                if (tot == n)
                    break;
                tot++;
                p[tot].x = i;
                p[tot].y = j;
            }
        }
    }
    cout << "Yes" << endl;
    for (int i = 1; i <= n; i++)
    {
    
    
        cout << p[i].x << " " << p[i].y << endl;
    }
}

signed main()
{
    
    
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
#ifdef FZT_ACM_LOCAL
   // freopen("in.txt", "r", stdin);
   // freopen("out.txt", "w", stdout);
#else
    ios::sync_with_stdio(false);
    int T = 1;
    cin >> T;
    while (T--)
        solve();
#endif
    return 0;
}

猜你喜欢

转载自blog.csdn.net/fztsilly/article/details/107493226