Tyvj1208(LIS数量)

题目链接

分析:
之前在xym的hu测中做过这道题,但是代码是急急忙忙码的
理解不是很深刻,题解说的也不好
所以只能再来学习一遍

第一问nlogn,不要写错了

第二问
这次是最长上升子序列

记g[i]为以i结尾,长度是f[i]的子序列的所有方案数

对于每个f[i]=k来说
ta都可能是由f[j]=k-1(j

对于f[j]=k-1所有的j

如果从小到大排序,那么一定有a[j]>=a[j+1]

因为如果a[j]

队中元素的a值单调递减

前端出队,后端入队
出队:队首元素的a**大于等于**当前转移点的a(a[i])
入队:如果f[i]==f[wei]&&a[i]==a[wei],wei–
a[i] < a[wei]时入队

开一ans数组,记录f值=i时,队列中的g值之和

最后计算答案的时候
f[i]==len
a[i]单调递减
利用这个性质,避免重复统计答案

tip

还是写代码时别手残

这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<algorithm>

using namespace std;

int f[1000],l[1000],n,m,a[1000];
int g[1000],len,ans[1000];
deque<int>q[1000];

void doit()
{
    l[1]=a[1];
    f[1]=1;
    int t=1;
    for (int i=2;i<=n;i++)
    {
        if (a[i]>l[t]) l[++t]=a[i],f[i]=t;
        else
        {
            int r=lower_bound(l+1,l+1+t,a[i])-l;
            l[r]=a[i];
            f[i]=r;
        }
    }
    printf("%d
",t);
    len=t;
}

void solve()
{
    int i,j;
    for (i=1;i<=n;i++)
    {
        if (f[i]==1) g[i]=1;
        else
        {
            int r=f[i]-1;
            while (!q[r].empty()&&a[q[r].front()]>=a[i])
            {
                ans[r]-=g[q[r].front()];
                q[r].pop_front();
            } 
            g[i]=ans[r];
        }
        int r=f[i];
        while (!q[r].empty()&&a[q[r].back()]==a[i]) 
        {
            ans[r]-=g[q[r].back()];
            q[r].pop_back();
        }
        ans[r]+=g[i];
        q[r].push_back(i);
    }
    int cnt=0,t=0;
    for (i=n;i>=1;i--)
        if (f[i]==len&&a[i]>t)
           cnt+=g[i],t=a[i];
    printf("%d",cnt);
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    doit();
    solve();
    return 0;
}
原文地址:https://www.cnblogs.com/wutongtong3117/p/7673183.html