bzoj 1307/1318 玩具 线段树+记录时间戳
玩具
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 743 Solved: 404
[Submit][Status][Discuss]
Description
小球球是个可爱的孩子,他喜欢玩具,另外小球球有个大大的柜子,里面放满了玩具,由于柜子太高了,每天小球球都会让妈妈从柜子上拿一些玩具放在地板上让小球球玩。
这天,小球球把所有的N辆玩具摆成一排放在地上,对于每辆玩具i,小球球都会给它涂上一个正整数value[i],以表示小球球对该玩具的喜爱程度,value[i]越小则表示他越喜爱。当然对于两辆不同的玩具u,v(u<>v),亦有可能value[i]=value[j],也就是说小球球对u,v两车的喜爱程度是一样的。
小球球很贪玩,他希望能从中间某个位置,连续的取出k辆玩具,使得这k辆车里喜爱程度最大的一辆车的喜爱程度正好等于k,且这k辆车中没有两辆车的喜爱程度是相同的。小球球希望知道k的最大值为多少。
Input
第一行一个整数N,表示小球球拥有的玩具数量。
接下来N行,每行一个整数,表示value[i]。
Output
一个整数k,即答案。
Sample Input
6
2
4
1
3
2
1
2
4
1
3
2
1
Sample Output
4
HINT
1<=Value[i]<=10^6
10%的测试数据 N<=10^5。
100%的测试数据 N<=10^6
Source
1318: [Spoj744] Longest Permutation
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 608 Solved: 366
[Submit][Status][Discuss]
Description
给你一个序列A含有n个正整数(1<=Ai<=n)。A的子集形式类如Au, Au+1 ... , Av (1<=u<=v<=n),即必须是连续的。我们感兴趣的是一种子集,它含有元素包括1,2,…k。(k是子集的大小)。
你的任务是找到这种类型的最长的子集。
Input
第一行,一个数n,表示序列A的长度
第二行,n个数,第I个数表示元素Ai
Output
一个数,表示可选子集的长度
Sample Input
5
4 1 2 3 2
4 1 2 3 2
Sample Output
4
HINT
你可以选得子集从A1开始到A4,这个子集长度为4,包含了1,2,3,4)
1<=n<=100010
Source
第一题直接划水,第二题想了想。
第二题题解:可以想到如果两个值相同的话是绝对不能在同一段的
并且它是要连续的,那我们每次加入一个节点时,求出以这个节点结尾的
最大值,怎么求,我用线段树来维护,这棵线段树是一棵权值线段树,
用full表示在这棵子树的所有叶节点是否都有了,然后每个节点记录最小,最大时间戳
表示当前子树中最早与最晚进来的时间,因为每个节点最多只会有一个时间戳,然后
对于删除,就是从头开始一旦两个相同,就将删除指针后移到当前相同的那一个位置+1
每次询问在线段树上二分,左子树如果满了,并且,是当前需要的最迟siz左子树节点就满足
然后去右子树,这是一个递归过程。
删除log n ,插入log n 每个值只会插入一次删除一次,正确答案一定有最右断点。
所以总复杂度O(n log n)
但是数据比较水,这两道题只需要输出序列的最大值即可。
1 #pragma GCC optimize(2) 2 #pragma G++ optimize(2) 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 #include<cstdio> 7 #include<cstring> 8 9 #define N 27 10 using namespace std; 11 inline int read() 12 { 13 int x=0,f=1;char ch=getchar(); 14 while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} 15 while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} 16 return x*f; 17 } 18 19 int n; 20 int a[N]; 21 22 int main() 23 { 24 n=read();int ans=0; 25 for (int i=1;i<=n;i++) 26 { 27 int x=read(); 28 ans=max(x,ans); 29 } 30 printf("%d\n",ans); 31 }