题目描述
看到这道题,比赛时当然没做出来。。。
然后在赛后补题时,知道了要用构造的方法
一、判断是否有解
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>=4sqrt(n).
所以m^2>=16n.
当m^2<n16时,无解
二、如何构造
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<bits/stdc++.h>
#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);
}
}
}
}