D Points Construction Problem(思维构造,等周定理)

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

题意:给定n和m,要求你在全白的二维坐标上点上n个黑点,要求相邻颜色互异的点对恰好为m对(点x和点y,点y和点x被认为是相同的点对)。

分析:这题很容易想到一些限制条件:

   1、n个黑点最多构成4n对点对,也就是m的上界为4*m;

   2、m只能为偶数,可以假设一开始n个黑点构成4n点对,要让点对减少只能黑点与黑点相邻建,而这种方法消去的点对数是相互的,也就是一定是偶数。

   关键是确立下界:

   1、可以想象,n个黑点要构成尽可能小的点对肯定是全部“凑”在一起;

   2、而由下图,俩图的点对都是14,也就是其周长2*(a+b),由此,因为周长一定,所以我们把n个点尽可能地“塞”成(a+b)较小的情况,这部分可直接暴力解决,得下界2*(a+b)

   

   接着是构造:

   1、由下界确定的步骤,我们可以一开始就把n个点设成下界,从上到下,从左到右。然后依次“挑出黑点”让其“孤立”。

   2、而“挑出黑点”的过程点对减少有2种情况:

 

   3、构造的过程就是“挑出黑点”的过程,最后只需将原本的和挑出的部分输出即为答案。

 

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define MP make_pair
#define pii pair<int,int>
typedef long long ll;
typedef unsigned long long ull;
const int mod=998244353;
const int inf=0x3f3f3f3f;
const ll INF=1e18;
vector<pii>ans1,ans2;
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int n,m,a,b,minn=inf;
        ans1.clear(),ans2.clear();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
            for(int j=1;j<=m;j++)
                if(i*j>=n&&(i-1)*j<n&&i*(j-1)<n){///要n个点能填充的矩形
                    if(2*(i+j)<minn){
                        minn=2*(i+j);
                        a=i,b=j;
                    }
                }

        if(m&1||m>4*n||m<minn){
            puts("No");
            continue;
        }


        for(int i=1;i<=a;i++)
            for(int j=1;j<=b;j++){
                if(n==0)
                    break;
                ans1.pb(MP(i,j));
                n--;
            }
        int now=minn;///当前点对
        int nowx=1000,nowy=1000;
        while(ans1.size()>1&&m>=now+4){
            pii tmp=ans1.back();
            ans1.pop_back();
            if(tmp.first==1||tmp.second==1)
                now+=2;
            else
                now+=4;
            ans2.pb(MP(nowx,nowy));
            nowx+=2;
        }
        if(m==now+2){
            pii tmp=ans1.back();
            ans1.pop_back();
            if(tmp.first==1||tmp.second==1)
                ans2.pb(MP(nowx,nowy));
            else
                ans2.pb(MP(tmp.first-1,b+1));///把贡献4的黑点拉到ans1的右侧,使其贡献为2
        }
        puts("Yes");
        for(auto it:ans1)
            printf("%d %d\n",it.first,it.second);
        for(auto it:ans2)
            printf("%d %d\n",it.first,it.second);
    }
    return 0;
}
View Code

 

posted @ 2020-07-23 22:53  starve_to_death  阅读(286)  评论(0编辑  收藏  举报