zoukankan      html  css  js  c++  java
  • 2019HDU多校第六场 HDU6635 Nonsense Time

    题意:给你一个n的排列p,再给你一个n的排列k,一开始所有p不可用,对于每个ki表示下标为k1~ki的p可用,求当前可用的所有p的最长上升子序列(可能表达的不是很清楚,这里看题面

    题解:题意等价于一个完整的排列按照一定顺序依次删除每个数,然后计算每次操作后的 LIS 长度。这样就好办了,首先在 O(nlogn) 的时间内求出 LIS,并记录一个 LIS(不会记录路径看这里),当删除 x 时,如果 x 不在之前找 到的那个 LIS 中,那么显然 LIS 的长度是不会变化的,否则暴力重新计算出新的 LIS 即可。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 50005, INF = 0x3f3f3f3f;
    int low[maxn], a[maxn], pos[maxn], k[maxn], ans[maxn];
    bool in[maxn],vis[maxn];
    int n, len;
    void LIS()
    {
        memset(low, INF, sizeof(low));
        memset(in,false,sizeof(in));
        int cnt=1;
        while(vis[cnt]==true)
        {
            cnt++;
        }
        low[1] = a[cnt];
        len = 1;
        pos[cnt] = len;
        for (int i = 2; i <= n; i++)
        {
            if(vis[i]==true)continue;
            if (a[i] > low[len])
            {
                low[++len] = a[i];
                pos[i] = len;
            }
            else
            {
                int index = lower_bound(low + 1, low + 1 + len, a[i]) - low;
                low[index] = a[i];
                pos[i] = index;
            }
        }
        //利用pos数组找到一个LIS,用in标记
        int maxx = INF,tem=len;
        for (int i = n; i >= 1; i--)
        {
            if (tem == 0)
                break;
            if (pos[i] == tem && maxx >= a[i])
            {
                in[i] = true;
                tem--;
                maxx = a[i];
            }
        }
    }
    int main()
    {
        int t;
        scanf("%d", &t);
        while (t--)
        {
            memset(pos,0,sizeof(pos));
            memset(vis,false,sizeof(vis));
            scanf("%d", &n);
            for (int i = 1; i <= n; i++)
            {
                scanf("%d", &a[i]);
            }
            LIS();
            for (int i = 1; i <= n; i++)
            {
                scanf("%d", &k[i]);
            }
            ans[n]=len;
            for (int i = n; i >= 2; i--)
            {
                vis[k[i]] = true;
                pos[k[i]] = 0;
                if (in[k[i]] == false)//如果不在现在的LIS上
                {
                    ans[i-1] = len;
                }
                else
                {
                    LIS();
                    ans[i-1] = len;
                }
            }
            for(int i=1;i<=n;i++)
            {
                printf("%d%s",ans[i],i==n?"
    ":" ");
            }
        }
        return 0;
    }
  • 相关阅读:
    Redis--过期键策略(惰性删除、定期删除)
    Redis--数据库(个数16、键空间、过期字典、过期策略)
    Redis--事件(serverCron)
    ArrayList是如何扩容的?
    Java的四大引用类型
    类加载机制,双亲委派模型及其优点
    GC调优思路
    modcount的作用
    JVM的常见的垃圾收集器
    什么是临界区?如何解决冲突(也就是临界区的调度原则)?
  • 原文地址:https://www.cnblogs.com/Zeronera/p/11317508.html
Copyright © 2011-2022 走看看