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;
}
posted @ 2020-10-21 20:50  When_C  阅读(92)  评论(0编辑  收藏  举报