1. 程式人生 > 實用技巧 >CF482A Diverse Permutation(貪心構造)題解

CF482A Diverse Permutation(貪心構造)題解

這裡給出一種構造方法及其證明

方法:考慮從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\)

\(n\)依次排列就行了。

證明:為什麼這樣構造是對的呢?

首先,由於是依次構造差值,所以肯定包含了\(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;
}