F. Greedy Sequence(The Preliminary Contest for ICPC Asia Nanjing 2019题解)

题目链接 

You're given a permutation aaa of length n (1≤n≤105).

For each i∈∈[1,n], construct a sequence sis_isi​ by the following rules:

  1. si​[1]=i;
  2. The length of si​ is n, and for each j∈[2,n], si​[j]≤si​[j−1];
  3. First, we must choose all the possible elements of si​ from permutation a. If the index of si​[j] in permutation aaa is pos[j], for each j≥2, ∣pos[j]−pos[j−1]∣≤k (1≤k≤105). And for each si​, every element of si​ must occur in aaa at most once.
  4. After we choose all possible elements for si​, if the length of si​ is smaller than nnn, the value of every undetermined element of si​ is 000;
  5. For each si​, we must make its weight high enough.

Consider two sequences C=[c1​,c2​,...cn​] and D=[d1​,d2​,...,dn​], we say the weight of C is higher than that of D if and only if there exists an integer kkk such that 1≤k≤n, ci​=di​ for all 1≤i<k, and ck​>dk​.

If for each i∈[1,n], ci​=di​, the weight of CCC is equal to the weight of D.

For each i∈[1,n], print the number of non-zero elements of si​ separated by a space.

It's guaranteed that there is only one possible answer.

Input

There are multiple test cases.

The first line contains one integer T(1≤T≤20), denoting the number of test cases.

Each test case contains two lines, the first line contains two integers nnn and k (1≤n,k≤105), the second line contains nnn distinct integers a1​,a2​,...,an​ (1≤ai​≤n) separated by a space, which is the permutation a.

Output

For each test case, print one line consists of nnn integers ∣s1​∣,∣s2​∣,...,∣sn​∣ separated by a space.

∣si​∣ is the number of non-zero elements of sequence sis_isi​.

There is no space at the end of the line.

Input
2
3 1
3 2 1
7 2
3 1 4 6 2 5 7
Output
1 2 3
1 1 2 3 2 3 3

题意:给出n,k,然后给出一个长度为n的序列A,构造n个序列Si。要求Si序列的开头必须是Ai,问每个序列的长度。看第二组样例,A[1]=3,在前k个和后k个元素中找一个小于A[1]的最大的数,找到这个数后在找这个数前k个到后k个小于他的最大的数,直到找不到为止。

第二组样例构造的序列:
1
2
3 1
4 3 1
5 2
6 5 2
7 5 2

思路:纯暴力当然会T,我们在这个基础上进行两次优化:一:例如第二组样例以4开头的序列,先找到3,但是发现在前面3已经找过了就没有必要在重新找了,直接把以3开头的序列的长度加过来即可。二:找左右k个数中小于当前数的最大的数,我们可以从当前数开始一直找小于它的数在这个区间中有没有存在过,找到就记录下来并跳出。

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<set>
#include<map>
#include<string>
#include<string.h>
#include<math.h>
#include<vector>
#include<queue>
#define maxn 100010
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int a[maxn];
int sum[maxn];
int id[maxn];
int m[maxn];
int main()
{
   int t,n,k;
   scanf("%d",&t);
   while(t--){
     memset(a,0,sizeof(a));
     memset(sum,0,sizeof(sum));
     memset(m,0,sizeof(m));
     scanf("%d %d",&n,&k);
     for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        id[a[i]]=i;
     }
     m[1]=0;
     for(int i=2;i<=n;i++){
        for(int j=i-1;j>=1;j--){
            if(abs(id[j]-id[i])<=k){
                m[i] = j;
                break;
            }
        }
     }
     int maxx,p;
     for(int i=1;i<=n;i++){
        sum[i] = 0;
        p = i;
        while(p!=0){
            maxx = m[i];
            if(sum[maxx] != 0){
                sum[i]=sum[i]+sum[maxx]+1;
                break;
            }
            sum[i]++;
            p = maxx;
        }
     }

      for(int i=1;i<=n;i++)
      {
          if(i != n)
            printf("%d ",sum[i]);
          else
            printf("%d\n",sum[i]);
      }
    }
   return 0;
}

发布了350 篇原创文章 · 获赞 715 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/ZCY19990813/article/details/100184311