题目
传送门 to AtCoder
思路
你看,其实每个人都会把 [1,n] 的所有编号拿一遍。所以,下面这句话就是顺理成章的:场地上的两个数字的差不能重复。
譬如,假设一个场地上是 (a,a+Δ) 而另一个是 (b,b+Δ) ,那么某两个编号相差 Δ 的人就会在这两个场地上都比赛。
类似的,二者的差可能不是正数。意即:一个人拿 a+Δ 而另一个人拿 a ,二者的编号差也可能是 a−(a+Δ)=−Δ≡n−Δ(modn) ,因为编号会自动取模 n 。当然,这种情况会在两个差值(大减小)的和为 n 时出现。
我们可以用集合来表示所有的差值。当 n 为奇数时,很好找到这样的差值 {1,3,5,…,n−2}
题面保证了 2m+1≤n 即 m≤2n−1 ,故数量足够。任意两者的和为奇数+奇数=偶数,不可能等于 n 。能够构造出来吗?使用 俄罗斯套娃 !
可以使用 (1,n−1),(2,n−2),(3,n−3),…,(2n−1,2n+1) 。
至于 n 为偶数的情况,就得动点小心思。我们可以写出这样的差值 {x∣∣∣2x∈Z,x<2n}⋃{x∣∣∣∣2x−1∈Z,x>2n}
个数有多少个?可以分类讨论 n/2 的奇偶性。在 n/2 为奇数时,大小为 (4n−21)+(4n−21)=2n−1 ,显然够用;在 n/2 为偶数时,大小为 (4n−1)+(4n)=2n−1 ,仍然够用。
相加会不会得到 n 呢?因为 n 是偶数,所以只能是奇数+奇数,或者偶数+偶数。但是奇数都小于 2n ,和必然小于 n ;偶数都大于 2n ,和必定大于 n ,故方案可行。
怎么构造呢?仍然使用俄罗斯套娃。小于 2n 的在最内层,更大的在外层继续套上去。
代码
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
int main(){
int n, m;
scanf("%d %d",&n,&m);
if(n%2 == 1){
int l = 1, r = n-1;
for(int i=1; i<=m; ++i)
printf("%d %d\n",l++,r--);
}
else if(n%2 == 0){
int l = n/2, r = n/2+1;
for(int i=1; i<=m; ++i){
printf("%d %d\n",l--,r++);
if((r-l)%2 and r-l >= n/2)
++ r;
}
}
return 0;
}