本题解同步更新于我的博客欢迎围观★,°:.☆( ̄▽ ̄)/$:.°★ 。
题意描述
构造一个到的排列,使得其中正好有个二元组满足, &&
做法分析
首先我们可以发现,每个数,它在序列能构成有用二元组的只有比他大的,那也就是说我们找到了排列的二元组最多情况,也就是到按从大到小顺序排列。
那进一步想,每个数在序列中最大能对他有用的数(即能构成二元组的)有多少个呢,发现对于每个数,满足的最大的再即为每个数的最大贡献,其实也就是。
这样就有了构造方法,对于每个不是(没有比大的数了)的数,如果,那就将减去其贡献值,并把他放到最后。
举个例子:
输入:5 5
得到:3 4 5 2 1
从开始,他的贡献最大是,可以与形成二元组,小于,于是减,标记一下被放到后面了。
再到,贡献是,可以与形成二元组,小于等于,于是减,标记一下被放到后面了,这时候已经等于了,即我们构造的排列已经符合要求。
这样应该就很清楚了,时间复杂度。
点个赞再走呗/kel
代码
#include <bits/stdc++.h>
using namespace std;
int n, k;
int flag1[1000010], flag2[1000010];
int lg[1000010];
int main()
{
scanf("%d%d", &n, &k);
for(int i = 2; i <= n; i++)
lg[i] = lg[i >> 1] + 1;
for(int i = 1; i <= n; i++)
flag1[i] = 1;
for(int i = 1; i < n; i++)
{
int cha = n - i;
if(lg[cha] + 1 <= k)
{
flag1[i] = 0;
flag2[i] = 1;
k -= lg[cha] + 1;
}
if(k == 0)
break;
}
if(k > 0)
{
printf("-1");
return 0;
}
for(int i = 1; i <= n; i++)
if(flag1[i])
printf("%d ", i);
for(int i = n; i >= 1; i--)
if(flag2[i])
printf("%d ", i);
return 0;
}