分析:
之前在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;
}