• [Codeforces261D]Maxim and Increasing Subsequence——树状数组+DP


    题目链接:

    Codeforces261D

    题目大意:$k$次询问,每次给出一个长度为$n$的序列$b$及$b$中的最大值$maxb$,构造出序列$a$为$t$个序列$b$连接而成,求$a$的最长上升子序列。$n,maxble10^5,maxb*nle2*10^7,tle10^9$。

    设$b$中不同数的个数为$sum$。如果$sumle t$,那么答案就是$sum$(只需要从第$i$个序列$b$中取第$i$小的数即可)。现在只需要考虑$t<sum$的情况,因为$sumle 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
    ",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
    ",ans);
    	}
    }
  • 相关阅读:
    clientX和clientY属性需要注意的地方
    事件冒泡 --- 仿select下拉框
    body和document的梗
    完美运动框架
    仿flash运动框架
    多物体运动框架
    Computed Styles
    悬浮框
    【一起驴友】公司笔试
    Client Dimensions , offsetHeight , scrollTop 属性详解
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/10441696.html
Copyright © 2020-2023  润新知