2020牛客暑期多校训练营(第三场)Points Construction Problem

题目描述

2020牛客暑期多校训练营(第三场)Points Construction Problem_第1张图片

看到这道题,比赛时当然没做出来。。。
然后在赛后补题时,知道了要用构造的方法

一、判断是否有解

1、点对的数量肯定是偶数,所以当m%2==1时,无解。
2、n个点,最多有4n个点对,所以当m>4n时,无解。
3、对于点为矩形时,设长为x,宽为y,则n=xy且2*(x+y)要尽量小。
所以2*(x+y)>=m>=22sqrt(xy)>=4sqrt(n).
所以m>=4
sqrt(n).
所以m^2>=16n.
当m^216时,无解

二、如何构造

1、当m >n*2+2时

可以先将一些点连成链,再将剩下的点孤立即可。
即:先算出有几个点不能与黑点相邻,再将剩下的点按链输出。

			if (m>2*n+2)
			{
				o=(m-(2*n+2))/2;p=n-o;
				for (i=1;i<=p;i++) printf("1 %lld\n",i);
				for (i=1;i<=o;i++) printf("4 %lld\n",i*2);
			}
2、当m<=n*2+2时

先造一个L型链,再往里面填充,每次填充后的点对数量不变

                o=m/4,p=m/2-o;
                for(i=1;i<=o;i++) printf("%lld 1\n",i);
                for(j=2;j<=p;j++) printf("1 %lld\n",j);
                l=n-(o+p-1);
                for(i=2;i<=o&&l>0;i++)
                    for(j=2;j<=p&&l>0;j++,l--)
                        printf("%lld %lld\n",i,j);

当全都构造好时,把程序补全即可

#include
#define ll long long
using namespace std;
ll T,n,m,i,j,k,l,o,p,a[10010][10010];
int main()
{
	for (scanf("%lld",&T);T--;)
	{
		scanf("%lld%lld",&n,&m);
		if(m&1||m>4*n||n*16>m*m) puts("No");
		else
		{
			puts("Yes");
			if (m>2*n+2)
			{
				o=(m-(2*n+2))/2;p=n-o;
				for (i=1;i<=p;i++) printf("1 %lld\n",i);
				for (i=1;i<=o;i++) printf("4 %lld\n",i*2);
			}
			else
			{
                o=m/4,p=m/2-o;
                for(i=1;i<=o;i++) printf("%lld 1\n",i);
                for(j=2;j<=p;j++) printf("1 %lld\n",j);
                l=n-(o+p-1);
                for(i=2;i<=o&&l>0;i++)
                    for(j=2;j<=p&&l>0;j++,l--)
                        printf("%lld %lld\n",i,j);
			}
		}
	}
}

你可能感兴趣的:(构造)