1. 程式人生 > >[Codeforces261D]Maxim and Increasing Subsequence——樹狀數組+DP

[Codeforces261D]Maxim and Increasing Subsequence——樹狀數組+DP

pro space 就是 printf 一個 queue bitset class color

題目鏈接:

Codeforces261D

題目大意:$k$次詢問,每次給出一個長度為$n$的序列$b$及$b$中的最大值$maxb$,構造出序列$a$為$t$個序列$b$連接而成,求$a$的最長上升子序列。$n,maxb\le10^5,maxb*n\le2*10^7,t\le10^9$。

設$b$中不同數的個數為$sum$。如果$sum\le t$,那麽答案就是$sum$(只需要從第$i$個序列$b$中取第$i$小的數即可)。現在只需要考慮$t<sum$的情況,因為$sum\le maxb$,所以$t<maxb$,這也就說明$n*t<n*maxb=2*10^7$,那麽序列長度最大為$2*10^7$,我們只需要$O(nlog_{n})$求序列的最長上升子序列即可。直接$DP$,$f[i]$表示前$i$個數的最長上升子序列長度,用樹狀數組存前綴最大值然後掃一遍整個序列$DP$即可。

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int sum;
int n,t,k;
int b[100010];
int a[20000010];
int v[100010];
int ans;
int maxb;
int f[20000010];
map<int,int>mp;
void add(int x,int k)
{
	for(int i=x;i<=maxb;i+=i&-i)
	{
		v[i]=max(v[i],k);
	}
}
int ask(int x)
{
	int res=0;
	for(int i=x;i;i-=i&-i)
	{
		res=max(res,v[i]);
	}
	return res;
}
int main()
{
	scanf("%d%d%d%d",&k,&n,&maxb,&t);
	while(k--)
	{
		memset(v,0,sizeof(v));
		mp.clear();
		sum=0;
		ans=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&b[i]);
			if(!mp[b[i]])
			{
				sum++;
				mp[b[i]]=1;
			}
		}
		if(t>=sum)
		{
			printf("%d\n",sum);
			continue;
		}
		for(int i=1;i<=n*t;i++)
		{
			a[i]=b[(i-1)%n+1];
		}
		for(int i=1;i<=n*t;i++)
		{
			f[i]=ask(a[i]-1)+1;
			ans=max(ans,f[i]);
			add(a[i],f[i]);
		}
		printf("%d\n",ans);
	}
}

[Codeforces261D]Maxim and Increasing Subsequence——樹狀數組+DP