CF482A Diverse Permutation(貪心構造)題解
阿新 • • 發佈:2020-10-21
這裡給出一種構造方法及其證明
方法:考慮從k開始依次構造差值,即第一個與第二個相差\(k\),第二個與第三個相差\(k-1\)。首先假設第一個數為\(1\),因此我們要把\(1+k\)放在第二個,那麼第三個數應該為\(1+k-(k - 1) = 2\),第四個為\(2+(k - 3) = k - 1\),第五個為\(k - 1 - (k - 2) = 3\),以此類推。
不難發現,其實整個序列的前半段就是由\(1,2,3...\)與\(k + 1, k, k - 1...\)插空排列成的,我們只需要設定兩個變數\(i\)與\(j\),分別從\(1\)開始遞增,從\(k+1\)開始遞減就行了。而剩下的就從\(k+2\)
證明:為什麼這樣構造是對的呢?
首先,由於是依次構造差值,所以肯定包含了\(k\)個差值。我們考慮前半段構造的種植條件,即\(i \geq j\)時,更確切地,就是當\(i=j\)或\(i = j + 1\)時。因此,前半段的最後一項為\(\lfloor\frac{k}{2}\rfloor\),而後半段的首項為\(k+2\),它們的差為\(\frac{k}{2}\)或\(\frac{k}{2}+1\),而這個差值肯定是包含在\(1-k\)之中的。
綜上,這一構造方法是正確的。
程式碼實現
#include <cstdio> using namespace std; const int maxn = 1e5 + 10; int n,k; int main(){ scanf("%d%d", &n, &k); int i = 1, j = i + k; while(1){ printf("%d %d ", i ++, j --); if(i >= j){ if(i == j) printf("%d ", i); break; } } for(int i = k + 2; i <= n; ++ i) printf("%d ", i); printf("\n"); return 0; }