【二分】【最长上升子序列】HDU 5489 Removed Interval (2015 ACM/ICPC Asia Regional Hefei Online)

题目链接:

  http://acm.hdu.edu.cn/showproblem.php?pid=5489

题目大意:

  一个N(N<=100000)个数的序列,要从中去掉相邻的L个数(去掉整个区间),使得剩余的数最长上升子序列(LIS)最长。

题目思路:

  【二分】【最长上升子序列】

  首先,假设去掉[i,i+m-1]这L个数,剩余的LIS长度为max(i左端最后一个不大于a[i+m]的LIS长度+a[i+m]开始到最后的LIS长度)。

  所以,我们从n到1逆向先求最长下降子序列的长度f[i],就可以知道每个数开始到结束的LIS。

  接着,从头开始做LIS,同时二分在前i个数中找最后一位比a[i+m]小的最长的LIS长度,更新答案。

  1 //
  2 //by coolxxx
  3 //#include<bits/stdc++.h>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<string>
  7 #include<iomanip>
  8 #include<map>
  9 #include<stack>
 10 #include<queue>
 11 #include<set>
 12 #include<bitset>
 13 #include<memory.h>
 14 #include<time.h>
 15 #include<stdio.h>
 16 #include<stdlib.h>
 17 #include<string.h>
 18 //#include<stdbool.h>
 19 #include<math.h>
 20 #define min(a,b) ((a)<(b)?(a):(b))
 21 #define max(a,b) ((a)>(b)?(a):(b))
 22 #define abs(a) ((a)>0?(a):(-(a)))
 23 #define lowbit(a) (a&(-a))
 24 #define sqr(a) ((a)*(a))
 25 #define swap(a,b) ((a)^=(b),(b)^=(a),(a)^=(b))
 26 #define mem(a,b) memset(a,b,sizeof(a))
 27 #define eps (1e-8)
 28 #define J 10000
 29 #define mod 1000000007
 30 #define MAX 0x7f7f7f7f
 31 #define PI 3.14159265358979323
 32 #define N 100004
 33 using namespace std;
 34 typedef long long LL;
 35 int cas,cass;
 36 int n,m,lll,ans;
 37 LL aans;
 38 int a[N],f[N],q[N];
 39 void getf()
 40 {
 41     int i,l,r,mid;
 42     lll=0;
 43     for(i=n;i;i--)
 44     {
 45         l=0,r=lll;
 46         while(l<r)
 47         {
 48             mid=(l+r+1)>>1;
 49             if(q[mid]>a[i])l=mid;
 50             else r=mid-1;
 51         }
 52         q[r+1]=a[i];
 53         f[i]=r+1;
 54         lll=max(lll,r+1);
 55     }
 56 }
 57 void work()
 58 {
 59     int i,l,r,mid;
 60     lll=0;
 61     for(i=1;i+m<=n;i++)
 62     {
 63         l=0,r=lll;
 64         while(l<r)
 65         {
 66             mid=(l+r+1)>>1;
 67             if(q[mid]<a[i+m])l=mid;
 68             else r=mid-1;
 69         }
 70         ans=max(ans,r+f[i+m]);
 71         l=0,r=lll;
 72         while(l<r)
 73         {
 74             mid=(l+r+1)>>1;
 75             if(q[mid]<a[i])l=mid;
 76             else r=mid-1;
 77         }
 78         q[r+1]=a[i];
 79         lll=max(lll,r+1);
 80     }
 81     ans=max(ans,lll);
 82 }
 83 int main()
 84 {
 85     #ifndef ONLINE_JUDGE
 86 //    freopen("1.txt","r",stdin);
 87 //    freopen("2.txt","w",stdout);
 88     #endif
 89     int i,j,k;
 90
 91 //    for(scanf("%d",&cass);cass;cass--)
 92     for(scanf("%d",&cas),cass=1;cass<=cas;cass++)
 93 //    while(~scanf("%s",s+1))
 94 //    while(~scanf("%d",&n))
 95     {
 96         ans=0;
 97         printf("Case #%d: ",cass);
 98         scanf("%d%d",&n,&m);
 99         for(i=1;i<=n;i++)scanf("%d",a+i);
100         getf();
101         work();
102         printf("%d\n",ans);
103     }
104     return 0;
105 }
106 /*
107 //
108
109 //
110 */

时间: 2024-08-09 04:44:34

【二分】【最长上升子序列】HDU 5489 Removed Interval (2015 ACM/ICPC Asia Regional Hefei Online)的相关文章

HDU 5489 Removed Interval 2015 ACM/ICPC Asia Regional Hefei Online

定义f[i]表示以i为开头往后的最长上升子序列,d[i]表示以i为结尾的最长上升子序列. 先nlogn算出f[i], 从i-L开始枚举f[i],表示假设i在LIS中得到的最长上升子序列,往[0,i-L)里找到满足ai>aj中dj值最大的.用dj+f[i]更新. 但是这样会少考虑一种情况,即i-L以后都不在最终的答案里面,这样一定是以[0~i-L)中的某个结尾的,所以还要用d[j]去更新答案. #include<bits/stdc++.h> using namespace std; con

【贪心】【模拟】HDU 5491 The Next (2015 ACM/ICPC Asia Regional Hefei Online)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5491 题目大意: 一个数D(0<=D<231),求比D大的第一个满足:二进制下1个个数在[s1,s2]范围内.D已经满足[s1,s2]. 题目思路: [贪心][模拟] 首先将这个数转成二进制统计总共1的个数s,再求出末尾连续0和1的个数n0,n1. 如果最后一位是0: s=s2,那么为了保证s<s2且答案>D,先设ans=d+lowbit(d),此时满足了新的s<s2且答案&g

HDU - 5491 The Next 2015 ACM/ICPC Asia Regional Hefei Online

从D+1开始,对于一个数x从它出发到x+lowbit(x)之前1的数量都是单调不减的,因此1的数量在一个范围内是一个区间. 每次判断一下有没有和[s1,s2]有没有交集. #include<bits/stdc++.h> using namespace std; inline int read() { char c; while(c=getchar(),c<'0'||c>'9'); int re = c-'0'; while(c=getchar(),c>='0'&&am

【线段树】HDU 5493 Queue (2015 ACM/ICPC Asia Regional Hefei Online)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5493 题目大意: N个人,每个人有一个唯一的高度h,还有一个排名r,表示它前面或后面比它高的人的个数,求按身高字典序最小同时满足排名的身高排列. 题目思路: [线段树] 首先可以知道,一个人前面或后面有r个人比他高,那么他是第r+1高或第n-i-r+1高,i为这个人是第几高的. 所以先将人按照身高从小到大排序,接下来,把当前这个人放在第k=min(r+1,n-i-r+1)高的位置. 用线段树维护包

Hdu 5442 Favorite Donut (2015 ACM/ICPC Asia Regional Changchun Online 最大最小表示法 + KMP)

题目链接: Hdu 5442 Favorite Donut 题目描述: 给出一个文本串,找出顺时针或者逆时针循环旋转后,字典序最大的那个字符串,字典序最大的字符串如果有多个,就输出下标最小的那个,如果顺时针和逆时针的起始下标相同,则输出顺时针. 解题思路: 看到题目感觉后缀数组可以搞,正准备犯傻被队友拦下了,听队友解释一番,果断丢锅给队友.赛后试了一下后缀数组果然麻烦的不要不要的(QWQ),还是最大最小表示法 + KMP来的干净利索. 最大表示法:对于一个长度为len文本串,经过循环旋转得到长度

【动态规划】HDU 5492 Find a path (2015 ACM/ICPC Asia Regional Hefei Online)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5492 题目大意: 一个N*M的矩阵,一个人从(1,1)走到(N,M),每次只能向下或向右走.求(N+M-1)ΣN+M-1(Ai-Aavg)2最小.Aavg为平均值. (N,M<=30,矩阵里的元素0<=C<=30) 题目思路: [动态规划] 首先化简式子,得原式=(N+M-1)ΣN+M-1(Ai2)-(ΣN+M-1Ai)2 f[i][j][k]表示走到A[i][j]格子上,此时前i+j-1

HDU 5491 The Next 构造(2015 ACM/ICPC Asia Regional Hefei Online)

[链接]click here~~ [题意]: 给你一个D(0≤D<231),保证D的二进制中1的数量在s1和s2之间 然后让你求一个最小的数,使得这个数的二进制数量大于等于s1,小于等于s2,且大于 d [思路]虽然是比赛时候的一道水题,但是开始看到的时候并没有想到好的思路,最后还是学弟强行过掉,今天突然想到了可以用lowbit来求 首先看到D的范围是很大的,那么如何 构造呢? 这里举个例子:比如11,二进制表示(1011),取11+1=12,二进制表示(1100)s1=2,那么我们要做的就是考

Hdu 5451 Best Solver (2015 ACM/ICPC Asia Regional Shenyang Online) 暴力找循环节 + 递推

题目链接: Hdu  5451  Best Solver 题目描述: 对于,给出x和mod,求y向下取整后取余mod的值为多少? 解题思路: x的取值为[1, 232],看到这个指数,我的心情是异常崩溃的.(吐血......) 可是仔细观察,它指数大,可是mod小啊,它吓人,可是可以暴力搞啊!! 这个题目一个难点就是要向下取整求余,详解见传送门,本题是向下取整,也就是向上取整加一. 还有就是指数太大,要找到循环节,其实由于mod小,循环节并没有太大,暴力跑就ok啦!  此刻内心是崩溃的 1 #i

Hdu 5452 Minimum Cut (2015 ACM/ICPC Asia Regional Shenyang Online) dfs + LCA

题目链接: Hdu 5452 Minimum Cut 题目描述: 有一棵生成树,有n个点,给出m-n+1条边,截断一条生成树上的边后,再截断至少多少条边才能使图不连通, 问截断总边数? 解题思路: 因为只能在生成树上截断一条边(u, v),所以只需要统计以v为根节点的子生成树里的节点与子生成树外的节点的边数就可以了.对于新加入的边(u', v')来说,只影响以LCA(u, v)为根节点的子树里面的节点.统计所有答案,扫一遍输出最小即可.(比赛的时候只统计叶子节点,给水过去了........233