运维开发网

2019ICPC南京网络赛F Greedy Sequence

运维开发网 https://www.qedev.com 2020-07-17 16:25 出处:网络 作者:运维开发网整理
题意:对于1<=i<=n每次找到(pos[i]-k,pos[i]+k)内不大于i的最大那个数,ans[i]=ans[mx]+1,若ans[mx]未知则递归处理ans[mx] PS:这个题比赛时写主席树k前驱没剪枝T了,然而实验室里的同学n^2过10w...自闭 主席树k前驱:在[l,r]范围内找到比k小的最大值,本质是带剪枝的主席树树上dfs 主要算法思想:当前区间[l,r]的sum(数字个数)为

题意:对于1<=i<=n每次找到(pos[i]-k,pos[i]+k)内不大于i的最大那个数,ans[i]=ans[mx]+1,若ans[mx]未知则递归处理ans[mx]

PS:这个题比赛时写主席树k前驱没剪枝T了,然而实验室里的同学n^2过10w...自闭

主席树k前驱:在[l,r]范围内找到比k小的最大值,本质是带剪枝的主席树树上dfs

主要算法思想:当前区间[l,r]的sum(数字个数)为0则剪枝,l==r时,如果l<k说明l是k的前驱,否则说明不存在k的前驱,查找时,如果k<=m+1(m=(l+r)/2)或者右区间不存在数字(数字个数为0)时,返回递归求左区间的答案(注意为什么是m+1,因为当k<=m+1时,小于k的值必定只可能出现在左区间[l,m]中),否则查找右区间,当递归右区间有解,则必为最优解,直接返回这个解即可,当右区间无解,才继续递归左区间求解

这样一系列剪枝以后,这个算法就可以跑的很快了!

其实还有个想法就是二分第k大值去求,这个思路比较简单而且复杂度是O(nlogn^2),不知道会不会T,有时间了尝试补上

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
struct Node
{
    int l,r,sum;
}node[N*40];//nlogn
int cnt;
int a[N],root[N];
void Insert(int l,int r,int pre,int& now,int val)
{
    node[++cnt]=node[pre];
    now=cnt;
    node[now].sum++;
    if(l==r)return;
    int m=(l+r)>>1;
    if(val<=m)Insert(l,m,node[pre].l,node[now].l,val);
    else Insert(m+1,r,node[pre].r,node[now].r,val);
}
int query(int L,int R,int l,int r,int k)
{
    if(node[R].sum-node[L].sum==0)return -1;
    if(l==r)return l<k?l:-1;
    int m=(l+r)>>1;
    if(k<=m+1||node[node[R].r].sum-node[node[L].r].sum==0)return query(node[L].l,node[R].l,l,m,k);
    int t=query(node[L].r,node[R].r,m+1,r,k);
    if(t!=-1)return t;
    return query(node[L].l,node[R].l,l,m,k);
}
int n,k;
int pos[N],dp[N];
int solve(int i)
{
    if(dp[i]!=-1)return dp[i];
    int l=max(1,pos[i]-k);
    int r=min(n,pos[i]+k);
    int res=query(root[l-1],root[r],1,n,i);
    if(res==-1)return dp[i]=1;
    return dp[i]=solve(res)+1;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin>>T;
    while (T--) {
        cnt=0;
        memset(dp,-1, sizeof(dp));
        memset(node,0, sizeof(node));
        cin >> n >> k;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            pos[a[i]]=i;
        }
        for (int i = 1; i <= n; i++) {
            Insert(1, n, root[i - 1], root[i], a[i]);
        }
        for(int i=1;i<=n;i++)
        {
            solve(i);
            cout<<dp[i]<<(i==n?‘\n‘:‘ ‘);
        }
    }
    return 0;
}

扫码领视频副本.gif

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号