題目
傳送門 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;
}