题意
给你一个长度为n的B数组,A表示B数组复制t遍后首尾相连后的数组,求A的最长上升子序列 有k组询问 ,maxb表示B数组中最大的数
原题&样例
分析
观察样例与数据可以知道,当t>=sum时,答案就是sum,其中sum为序列中不同数字的个数,因为是严格单调的。
那么,我们只考虑t<sum的情况。我们发现n∗maxb≤2∗107的,我们可以发现,这种情况下序列长度就是≤2*107,因为sum一定小于maxb。
然后dp,找最大值用树状数组。复杂度还是很恐怖的。在代码里面玄学优化就差不多了。
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
typedef long long ll;
using namespace std;
int k,n,maxb,t,sum,ans;
int a[100001],b[100001],c[100001],f[100001];
int lowbit(int x)
{
return x&(-x);
}
void change(int x,int y)
{
for(;x<=maxb;x+=lowbit(x))
{
c[x]=max(c[x],y);
}
}
int ask(int x)
{
int tmp=0;
for(;x!=0;x-=lowbit(x))
{
tmp=max(tmp,c[x]);
}
return tmp;
}
int main()
{
cin>>k>>n>>maxb>>t;
while(k--)
{
sum=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(b[a[i]]!=k+1)
{
sum++;
}
b[a[i]]=k+1;
}
if(t>=sum)
{
cout<<sum<<endl;
continue;
}
ans=0;
for(int i=1;i<=100001;i++)//清空数组
{
c[i]=0;
f[i]=0;
}
for(int i=1;i<=t;i++)
{
for(int j=1;j<=n;j++)
{
int y=ask(a[j]-1)+1;
if(y>f[j])
{
f[j]=y;
ans=max(ans,y);
change(a[j],y);
}
if(ans>=sum) break;
}
}
cout<<ans<<endl;
}
return 0;
}