[刷题]ACM ICPC 2015合肥网络赛 - Removed Interval

8 篇文章 0 订阅

Problem Description

Given a sequence of numbers A=a1,a2,…,aN, a subsequence b1,b2,…,bk of A is referred as increasing if b1

Input

The first line of input contains a number T indicating the number of test cases (T≤100).
For each test case, the first line consists of two numbers N and L as described above (1≤N≤100000,0≤L≤N). The second line consists of N integers indicating the sequence. The absolute value of the numbers is no greater than 109 .
The sum of N over all test cases will not exceed 500000.

Output

For each test case, output a single line consisting of “Case #X: Y”. X is the test case number starting from 1. Y is the maximum length of LIS after removing the interval.

Sample Input

2
5 2
1 2 3 4 5
5 3
5 4 3 2 1

Sample Output

Case #1: 3
Case #2: 1

Source

2015 ACM/ICPC Asia Regional Hefei Online

Key

啊被这题折磨了两天。最后发现是我数据范围错了。。题目说“The absolute value of the numbers is no greater than 109 ”,我理解成 [1,19) 了。。。

LIS题的一个变种。用 O(n2) 的DP做是没法做的, O(n2) 本身就超时了,更别说别的处理。得用 O(nlogn) 的那个算法。

基本思路是,先计算出以每个 A[i] 为开头的LIS(即从右向左找以 A[i] 结尾的最大降序子序列)。
然后枚举所有挖掉的连续字串的位置:对于挖掉的 [iL,i1] (i>L) ,LIS最大值为右侧以 A[i] 打头时的LIS加上左侧以比 A[i] 小的值结尾的最大LIS。

于是关键是怎么在左侧找出一个以 A[iL1] 结尾的LIS,要求LIS尽量大且 A[iL1]<A[i] 。查了题解,才知道可以利用那个 O(nlogn) 算法,二分找出在左侧x个值中小于A[i]的最大LIS。真是太强了。

Code

#include<functional>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int Maxn = 100000 + 10;

int T, N, L;
int A[Maxn], LIS[Maxn], BG[Maxn];

int main() {
    //freopen("F:\\Projects\\ConsoleApplication2\\ConsoleApplication2\\in.txt", "r", stdin);
    //freopen("F:\\Projects\\Debug Tools\\Comparison1.txt", "w", stdout);
    ios::sync_with_stdio(false);
    cin >> T;
    for (int Case = 1; Case <= T; ++Case) {
        cin >> N >> L;
        for (int i = 0; i < N; ++i) {
            cin >> A[i];
        }

        int res = 0;
        int len, idx;
        len = 1;
        LIS[0] = 0x7fffffff;
        for (int i = N - 1; i >= 0; --i) {
            idx = lower_bound(LIS, LIS + len, A[i], greater<int>()) - LIS;
            if (idx == len) ++len;
            LIS[idx] = A[i];
            BG[i] = idx;
            if (i >= L) res = max(res, idx);
        }

        len = 1;
        LIS[0] = 0x80000000;
        for (int i = L; i < N; ++i) {
            idx = lower_bound(LIS, LIS + len, A[i], less<int>()) - LIS;
            res = max(res, BG[i] + idx - 1);

            idx = lower_bound(LIS, LIS + len, A[i - L], less<int>()) - LIS;
            if (idx == len) ++len;
            LIS[idx] = A[i - L];
            res = max(res, idx);
        }

        printf("Case #%d: %d\n", Case, res);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值