• 最长什么什么子序列进阶(xym的hu测)


    这里写图片描述
    这里写图片描述

    分析:

    变成最长上升子序列

    第二问一眼dp
    但是没有什么用,不会啊STO

    第一问nlogn
    第二问
    dp的思路,设g[i]为以i结尾,长度是f[i]的子序列的所有方案数
    我们把f[j]=f[i]-1的所有j(j < i)从小到大依次选出来,
    它们的a[j]是单调不升的,

    因为f值等于f[i]-1的编号从小到大,
    如果存在k < j,a[k ]< a[j],那么f[j]=f[k]+1
    j,k在这种情况下是不可能同时转移到i的

    这样我们就可以按f[i]值把元素放到不同的集合里

    深入考虑集合中的数
    例如,我们要转移f[i]=k的点,
    显然f[i]=k-1所代表的转移点集合中a[i]单调不升,
    而且所有f[i]=k的这些被转移的点中a[i]也是单调不升的
    (这个和f[k]=k-1是一个道理啊)

    也就是说,假如f[j]=k-1,f[i]=k,j < i,但a[j]>=a[i],
    显然j不能作为i的转移点,
    那么对于比i大的那些i’(f[i’]=k),
    j更不可能是i’的转移点了,
    因为a[i’] <= a[i]

    这样我们就可以开若干个队列q[]来存储转移点
    保证每个队列中的a[i]单调递减,
    相应的弹出队首队尾元素
    再开个数组记录每个队列中g[i]的和即可
    开一个双端队列即可,可以用STL的deque也可以手写
    (不过开n个STL的deque巨慢,在cena里直接会T)

    tip

    很少用stl
    所以代码用的deque
    (感觉stl确实方便,废话。。。)

    队列里的元素编号从小到大,
    a值单调减

    我们要新开一个数组ans
    计算每一个队列中的元素和,
    这样在转移的时候就变成O(1)的了
    因为对于f[i]=k的转移,
    等于f值等于k的a[i]按编号排序的话一定是单调不升的
    所以直接修改ans来优化转移

    再说一下队首和队尾的出队条件
    队首
    在进行转移的时候维护出队,因为队列中的a一定是单调不升的
    所以一旦ai

    这里写代码片
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define ll long long
    
    using namespace std;
    
    const int mod=1000000007;
    const int N=300005;
    ll a[N],f[N],len,g[N],ans[N],l[N];
    deque <int> q[N];    //双端队列
    int n; 
    
    ll mo(ll a,ll b)
    {
        if (a+b>=0) return (a+b)%mod;
        else return (a+b+mod)%mod;
    }
    
    void doit()
    {
        int i,j,k;
        len=1;
        l[1]=a[1]; f[1]=1;
        for (i=2;i<=n;i++)
        {
            if (a[i]>l[len]) 
            {
                l[++len]=a[i];
                f[i]=len;
                continue;
            }
            int r=lower_bound(l+1,l+1+len,a[i])-l;
            l[r]=a[i];
            f[i]=(ll)r;
        }
        printf("%lld ",len);
        //for (i=1;i<=n;i++) printf("%d ",f[i]);
    }
    
    void solve()
    {
        int i,j;
        for (i=1;i<=n;i++)
        {
            if (f[i]==1) g[i]=1;   //dp的初始值
            else
            {
                ll p=f[i]-1;  //转移点的f
                while (!q[p].empty()&&a[q[p].front()]>=a[i])  //严格上升
                {
                    ans[p]=mo(ans[p],-g[q[p].front()]);  //无法转移的状态g值减掉 
                    q[p].pop_front();
                } 
                g[i]=ans[p]; 
            } 
            ll p=f[i];  //加入队列 
            while (!q[p].empty()&&a[q[p].back()]==a[i])  //值相同保存后
            {
                ans[p]=mo(ans[p],-g[q[p].back()]);
                q[p].pop_back();
            } 
            q[p].push_back(i);
            ans[p]=mo(ans[p],g[i]);
        }    
        ll cnt=0,t=0;
        for (i=n;i;i--)
            if (f[i]==len&&a[i]>t)   //防止值相同的元素g重复统计 
               cnt=mo(cnt,g[i]),t=a[i];
        printf("%lld",cnt);
    }
    
    int main()
    {
        freopen("seq.in","r",stdin);  
        freopen("seq.out","w",stdout);  
        scanf("%d",&n);
        for (int i=n;i>=1;i--)  scanf("%lld",&a[i]);
        doit();
        solve();
        return 0;
    }
  • 相关阅读:
    9 jmeter之检查点
    8 jmeter之集合点
    7 jmeter之参数化
    6 jmeter元件的作用域与执行顺序
    5 jmeter性能测试小小的实战
    4 jmeter badboy脚本开发技术详解
    3 jmeter的两种录制方法
    2 jmeter常用功能介绍-测试计划、线程组
    Errors occurred during the build. Errors running builder 'DeploymentBuilder' on project
    常见异常总结
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673413.html
Copyright © 2020-2023  润新知