最长上升子序列(LIS)(DP练习)

G - 最长上升子序列(LIS) Easy

Time limit2000 msMemory limit65536 kBOSLinux

A numeric sequence of ai is ordered if a1 < a2 < … < aN. Let the subsequence of the given numeric sequence ( a1, a2, …, aN) be any sequence ( ai1, ai2, …, aiK), where 1 <= i1 < i2 < … < iK <= N. For example, sequence (1, 7, 3, 5, 9, 4, 8) has ordered subsequences, e. g., (1, 7), (3, 4, 8) and many others. All longest ordered subsequences are of length 4, e. g., (1, 3, 5, 8).

Your program, when given the numeric sequence, must find the length of its longest ordered subsequence.
Input
The first line of input file contains the length of sequence N. The second line contains the elements of sequence - N integers in the range from 0 to 10000 each, separated by spaces. 1 <= N <= 1000
Output
Output file must contain a single integer - the length of the longest ordered subsequence of the given sequence.
Sample Input
7
1 7 3 5 9 4 8
Sample Output
4

题意:求最长上升子序列
分析:直接DP
用的二分 时间复杂度O(nlogn)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mem(a,n) memset(a,n,sizeof(a))
const int N=1e3+5;
const int INF=0x3f3f3f3f;
int dp[N],a[N];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        mem(dp,INF);
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        for(int i=0;i<n;i++)
        {
            *lower_bound(dp,dp+n,a[i])=a[i];
        }
        printf("%d\n",lower_bound(dp,dp+n,INF)-dp);
    }
    return 0;
}

必要的时候可以为了节省空间,用变量x代替a[i],边输入边插入

H - 最长上升子序列(LIS) Medium1
Time limit1000 msMemory limit32768 kBOSWindows
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹.
怎么办呢?多搞几套系统呗!你说说倒蛮容易,成本呢?成本是个大问题啊.所以俺就到这里来求救了,请帮助计算一下最少需要多少套拦截系统.
Input
输入若干组数据.每组数据包括:导弹总个数(正整数),导弹依此飞来的高度(雷达给出的高度数据是不大于30000的正整数,用空格分隔)
Output
对应每组数据输出拦截所有导弹最少要配备多少套这种导弹拦截系统.
Sample Input
8 389 207 155 300 299 170 158 65
Sample Output
2
分析:每次存储最小的那个
代码和上一题差不多,只是数组大小不同

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mem(a,n) memset(a,n,sizeof(a))
const int N=3e5+5;
const int INF=0x3f3f3f3f;
int a[N],dp[N];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        mem(dp,INF);
        for(int i=0; i<n; i++)
            scanf("%d",&a[i]);
        for(int i=0; i<n; i++)
        {
            *lower_bound(dp,dp+n,a[i])=a[i];
        }
        printf("%d\n",lower_bound(dp,dp+n,INF)-dp);
    }
    return 0;
}

I - 最长上升子序列(LIS) Medium2
Time limit1000 msMemory limit32768 kBOSWindows
JGShining’s kingdom consists of 2n(n is no more than 500,000) small cities which are located in two parallel lines.

Half of these cities are rich in resource (we call them rich cities) while the others are short of resource (we call them poor cities). Each poor city is short of exactly one kind of resource and also each rich city is rich in exactly one kind of resource. You may assume no two poor cities are short of one same kind of resource and no two rich cities are rich in one same kind of resource.

With the development of industry, poor cities wanna import resource from rich ones. The roads existed are so small that they’re unable to ensure the heavy trucks, so new roads should be built. The poor cities strongly BS each other, so are the rich ones. Poor cities don’t wanna build a road with other poor ones, and rich ones also can’t abide sharing an end of road with other rich ones. Because of economic benefit, any rich city will be willing to export resource to any poor one.

Rich citis marked from 1 to n are located in Line I and poor ones marked from 1 to n are located in Line II.

The location of Rich City 1 is on the left of all other cities, Rich City 2 is on the left of all other cities excluding Rich City 1, Rich City 3 is on the right of Rich City 1 and Rich City 2 but on the left of all other cities … And so as the poor ones.

But as you know, two crossed roads may cause a lot of traffic accident so JGShining has established a law to forbid constructing crossed roads.

For example, the roads in Figure I are forbidden.
这里写图片描述

In order to build as many roads as possible, the young and handsome king of the kingdom - JGShining needs your help, please help him. ^_^
Input
Each test case will begin with a line containing an integer n(1 ≤ n ≤ 500,000). Then n lines follow. Each line contains two integers p and r which represents that Poor City p needs to import resources from Rich City r. Process to the end of file.
Output
For each test case, output the result in the form of sample.
You should tell JGShining what’s the maximal number of road(s) can be built.
Sample Input
2
1 2
2 1
3
1 2
2 3
3 1
Sample Output
Case 1:
My king, at most 1 road can be built.

Case 2:
My king, at most 2 roads can be built.

Hint
Huge input, scanf is recommended.
题意:有n组贫穷和富有的城市,每组城市间需要修路,问最多可以修多少条路(每两条路之间不能有交叉,即没有十字路口)?
分析:从题意知道,城市间的关系与输入的顺序无关,那么将他们从小到大排序后,再找最长上升子序列就是题目所求

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mem(a,n) memset(a,n,sizeof(a))
const int N=5e5+5;
const int INF=0x3f3f3f3f;
int dp[N],a[N];
struct Node
{
    int x,y;
    bool operator < (const Node& m)const
    {
        if(x!=m.x)
            return x<m.x;
        return y<m.y;
    }
} p[N];
int main()
{
    int n,cas=1;
    while(~scanf("%d",&n))
    {
        mem(dp,INF);
        for(int i=0; i<n; i++)
            scanf("%d%d",&p[i].x,&p[i].y);
        sort(p,p+n);
        for(int i=0; i<n; i++)
        {
            *lower_bound(dp,dp+i,p[i].y)=p[i].y;
        }
        int ans=lower_bound(dp,dp+n,INF)-dp;
        printf("Case %d:\n",cas++);
        if(ans==1)
            printf("My king, at most 1 road can be built.\n\n");///单数形式
        else printf("My king, at most %d roads can be built.\n\n",ans);///复数
    }
    return 0;
}

J - 最长上升子序列(LIS) Hard
Time limit1000 msMemory limit262144 kB
You are given an array of positive integers a1, a2, …, an × T of length n × T. We know that for any i > n it is true that ai = ai - n. Find the length of the longest non-decreasing sequence of the given array.

Input
The first line contains two space-separated integers: n, T (1 ≤ n ≤ 100, 1 ≤ T ≤ 107). The second line contains n space-separated integers a1, a2, …, an (1 ≤ ai ≤ 300).

Output
Print a single number — the length of a sought sequence.

Example
Input
4 3
3 1 4 2
Output
5
Note
The array given in the sample looks like that: 3, 1, 4, 2, 3, 1, 4, 2, 3, 1, 4, 2. The elements in bold form the largest non-decreasing subsequence.

题意:有T个重复的长度为n的序列,求最长非递减子序列 的长度(1 ≤ n ≤ 100, 1 ≤ T ≤ 107). 序列中数据范围(1 ≤ ai ≤ 300).
先从样例着手,
n=4,T=3,此时n<T,n本身也比较小,最大为100,可以承受O(n^2)的,可以直接计算,
但是当T比较大时,特别是T>n=100时,这样直接计算会TLE,那么就不能直接这样写了
先来想个特殊情况,

  1. T>n,n=100且100个元素中各不相同且非递减,那么容易知道整个序列最长非递减的子序列长度为 (T-100)*1+100 ; 若n个元素是数据范围内任意的呢? 就求出n个元素中重复出现次数(mxlen)最多的,
    然后就可以得到答案 (T-n)*mxlen+tmp,tmp为n*n个元素的最长非递减序列的长度
  2. T<=n , tmp就是n*T个元素的最长非递减序列的长度 答案就是tmp
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <sstream>
#include <set>
using namespace std;
#define mem(a,n) memset(a,n,sizeof(a))
typedef long long LL;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const int N=1e2+5;
int cnt[3*N],a[N*N],dp[N*N];
int main()
{
    int n,T;
    while(~scanf("%d%d",&n,&T))
    {
        mem(dp,INF);///初始化
        int tolen,mxlen=0,ans_len=0;
        for(int i=0; i<n; i++)
        {
            scanf("%d",&a[i]);
            cnt[a[i]]++;
            mxlen=max(mxlen,cnt[a[i]]);///mxlen为n个元素中重复元素次数最多的次数
        }
        if(T>n) tolen=n*n,ans_len+=(T-n)*mxlen;///T>n时,此处的tolen就是分析中的tmp
        else tolen=n*T;
        for(int i=n; i<tolen; i++)///RT
            a[i]=a[i-n];
        for(int i=0; i<tolen; i++)
            *upper_bound(dp,dp+i,a[i])=a[i];///这里求的是最长非递减子序列,所以是upper_bound()
        //for(int i=0; i<tolen; i++)
         //   printf("dp[%d]=%d\n",i,dp[i]);
        ans_len+=lower_bound(dp,dp+tolen,INF)-dp;
        printf("%d\n",ans_len);
    }
    return 0;
}

以上几题解题方法共同点:
1.用了二分法,降低了时间复杂度为O(nlogn),当n较大时,不会T,(当然,你的想法不要极端,那种一定会让人T的就算了) 不用二分的话就是O(n^2),有的会T
2.二分的思想 用的比较好,而且在这几道题中通用,具体实现见:https://www.felix021.com/blog/read.php?1587
二分用法:上升用lower_bound(),非递减用upper_bound()

吐槽自己,,, 手抖了,之前写的很详细易懂的被自己不小心弄没了,重写了一次。。。
不过应该也挺好懂的。。 手抖。。

以上都是自己的想法,不对之处欢迎指出,不胜感激!

波浪子序列 Wavio Sequence UVA - 10534
链接:https://vjudge.net/problem/UVA-10534
题解: http://blog.csdn.net/feng_zhiyu/article/details/77503838

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值