UESTC 电子科大专题训练 DP-G

UESTC 1006

题意:找出LIS并输出其中字典序最小的一个序列

思路:一开始的想法是找出LIS用dp[i]保存以ai为结尾的LIS,然后从后面往前每次找出每一位的最小值,然后想了一下觉得不行,因为可能找到第k位的最小的位置p之后,第k-1位的最小值可能在p的后面,这样就导致找不到最小的字典序,但其实这种情况是不存在的,因为由LIS的性质(s[i]<s[i+1]) ,可以知道,如果dp[i] = dp[j]  && i<j --->一定可以推得a[i]>=a[j] ,因为如果a[i]<a[j] 那么意味着a[i]到a[j]也可以形成一个上升序列,那么必然得不到 dp[i]=dp[j]的前提,所以可知,dp[i]相等的前提下ai最小的一定在最后面,所以只需要从最后面往前依次取最靠右的且dp值依次为 cnt-->1 就可以了,由于开始没有想到这个结论,所以我用另一种方法写的,存2个数组,dp1 dp2,dp1[i]的意义如上述,dp2[i]表示以i为开始的LIS,那么可以得到,dp1[i]+dp2[i]-1的值便是ai所在的上升序列的最大长度,如果结果等于cnt说明ai是其中某个LIS的第dp1[i]位,遍历找出每一位的最小即可,这里把2种方法的代码都贴上来

AC代码:

1

#include "iostream"
#include "string.h"
#include "stack"
#include "queue"
#include "string"
#include "vector"
#include "set"
#include "map"
#include "algorithm"
#include "stdio.h"
#include "math.h"
#define ll long long
#define bug(x) cout<<x<<" "<<"UUUUU"<<endl;
#define mem(a) memset(a,0,sizeof(a))
#define mp(x,y) make_pair(x,y)
using namespace std;
const long long INF = 1e18+1LL;
const int inf = 1e9+1e8;
const int N=1e5+100;
const ll mod=1e9+7;

int dp1[1005];
int main(){
    int T;
    cin>>T;
    while(T--){
        mem(c),mem(dp1);
        cin>>n>>a[1];
        c[0]=-inf,c[1]=a[1],dp1[1]=1,cnt=0;
        for(int i=2; i<=n; ++i){
            cin>>a[i];c[i]=inf;
            int l=0,r=i-1,ans=0;
            while(l<=r){
                int mid=l+r>>1;
                if(c[mid]<a[i]){
                    ans=mid;
                    l=mid+1;
                }
                else r=mid-1;
            }
            dp1[i]=ans+1;
            cnt=max(cnt,ans+1);
            c[ans+1]=min(c[ans+1],a[i]);
        }
        cout<<cnt<<" ";
        int ct[N],p=cnt;mem(ct);
        for(int i=n; i>=1; --i){
            if(dp1[i]==p){
                ct[p]=a[i];
                p--;
            }
        }
        for(int i=1; i<=cnt; ++i){
            cout<<ct[i]<<" ";
        }
        cout<<"\n";
    }
    return 0;
}

2

#include "iostream"
#include "string.h"
#include "stack"
#include "queue"
#include "string"
#include "vector"
#include "set"
#include "map"
#include "algorithm"
#include "stdio.h"
#include "math.h"
#define ll long long
#define bug(x) cout<<x<<" "<<"UUUUU"<<endl;
#define mem(a) memset(a,0,sizeof(a))
#define mp(x,y) make_pair(x,y)
using namespace std;
const long long INF = 1e18+1LL;
const int inf = 1e9+1e8;
const int N=1e5+100;
const ll mod=1e9+7;

int a[1005],c[1005],dp1[1005],dp2[1005],n,cnt;

int main(){
    //ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int T;
    cin>>T;
    while(T--){
        mem(c),mem(dp1),mem(dp2);
        cin>>n>>a[1];
        c[0]=-inf,c[1]=a[1],dp1[1]=1,cnt=0;
        for(int i=2; i<=n; ++i){
            cin>>a[i];c[i]=inf;
            int l=0,r=i-1,ans=0;
            while(l<=r){
                int mid=l+r>>1;
                if(c[mid]<a[i]){
                    ans=mid;
                    l=mid+1;
                }
                else r=mid-1;
            }
            dp1[i]=ans+1;
            cnt=max(cnt,dp1[i]);
            c[ans+1]=min(c[ans+1],a[i]);
        }
        dp2[n]=1;
        for(int i=n-1; i>=1; --i){
            dp2[i]=1;
            for(int j=i+1; j<=n; ++j){
                if(a[j]>a[i]){
                    dp2[i]=max(dp2[i],dp2[j]+1);
                }
            }
        }
        int ct[1005];
        memset(ct,63,sizeof(ct));
        for(int i=1; i<=n; ++i){
            if(dp1[i]+dp2[i]==cnt+1){
                ct[dp1[i]]=min(ct[dp1[i]],a[i]);
            }
        }
        cout<<cnt<<" ";
        for(int i=1; i<=cnt; ++i){
            cout<<ct[i]<<" ";
        }
        cout<<endl;
    }
    return 0;
}
时间: 2024-10-15 05:09:13

UESTC 电子科大专题训练 DP-G的相关文章

UESTC 电子科大专题训练 数论 G

UESTC 1718 题意:在01串中选出长度为偶数,并且前一半是0,后一半是1的子序列方案数 思路:组合数+范德蒙恒等式 记录每个数前面0的个数pi和后面1的个数nexi(包括本身)遍历到第k个数的时候,如果是0 那么方案数为(因为计算第i位时,前面计算的i-1个答案都不包含这一位,但是第i位计算的答案都包含第i位 所以没有重复) for(i=0, -> i=min(pi-1,nexi)) C(pi-1,i)*C(nexi,i+1) 可以由 C(l-1,i)=C(l,i+1)-C(l-1,i+

UESTC 电子科大专题训练 DP-F

UESTC 1271 题意:有一个n*m的地图,每个格子有一定数量的金子,如果是负数,说明是陷阱,将会失去金子,如果金子数小于0就会死掉,你可以往四个方向走,分别是:(x+1,y),(x,y+1),(x+1,y+2)(x+1,y),(x,y+1),(x+1,y+2)and(x+2,y+1) 问最多可以获得多少金子 思路:每一个格子最多可以通过4个方向到达,可推得递推式为 dp[i][j]=max(dp[i-1][j],dp[i][j-1],dp[i-1][j-2],dp[i-2][j-2])+g

UESTC 电子科大专题训练 数论 L

UESTC 1723 题意:中文题 思路:预处理,dp[i][j]表示将j个人放到i个房间里,则可以得到dp[i][j]=dp[i][j-1]*i + dp[i-1][j-1],递推式的理解,第一:当有i个房间,j-1个人的时候方案数已知为dp[i][j-1],则当增加一个人的时候,第j个人可以选择i个房间的任意一个,或者选择一个新的房间,但是只有选择已有的i个房间才能递推得dp[i][j],第二:当有i-1个房间,j-1个人时,增加一个人,这个人有i+1种选择(i种选择为选择已有的房间,第i+

UESTC 电子科大专题训练 DP-E

UESTC 1652 题意:中文题 思路:遍历每一公里,然后计算每个车道对后一公里做出的贡献,最边上的车道特判,遍历完所有车道后判断如果车道上有障碍,那么这公里的的这个车道的概率为0,数据比较水,如果数据大可以用矩阵快速幂对每2个障碍之间用矩阵快速幂优化,这里就不写了 AC代码: #include "iostream" #include "iomanip" #include "string.h" #include "stack"

UESTC 电子科大专题训练 数据结构 D

UESTC 1584 题意:平面坐标上有n个怪物,每个怪物有一个rank值,代表x坐标和y坐标都不大于它本身的怪物数(不包括本身) 思路:对x y坐标从小到大排序,x优先排序,用数状数组计算y坐标小于它的数量 AC代码: #include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #i

UESTC 电子科大专题训练 数据结构 A

UESTC 1591 题意:求区间极值之差 思路:线段树裸题,不带更新 ACA代码: #include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set" #include "ma

UESTC 电子科大专题训练 数据结构 J

UESTC 1599 题意:中文题..不写了 思路:优先对列,小的优先 AC代码: #include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set" #include "map

UESTC 电子科大专题训练 数据结构 N

UESTC 1586 题意:中文题 思路:拆点并查集裸题 AC代码: #include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set" #include "map"

UESTC 电子科大专题训练 数据结构 L

UESTC 1594 题意:中文题 思路:和poj食物链的题几乎一样,拆点或者带权并查集做,这种分类不多的比较倾向与拆点做 AC代码: #include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "se