2018浙江省赛 E题 ZOJ4028 LIS

 

LIS


Time Limit: 1 Second      Memory Limit: 65536 KB      Special Judge

 

Sample Input

4
6
1 2 3 2 4 3
0 5
2 4
3 3
1 2
3 5
1 5
5
1 2 1 3 1
100 200
200 300
200 400
400 500
100 500
7
1 2 3 1 1 4 2
0 3
0 3
0 3
0 3
0 3
0 3
0 3
2
1 1
1 2
2 3

Sample Output

1 2 3 2 5 3
200 300 200 500 200
0 1 2 0 0 3 1
2 2
【题目链接】http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4028
【题意】给定一个数组f[],f[i]表示以第i个字符为终点的最长上升子序列长度,然后输入n行,每行有一个区间[l,r],表示第i个数字的取值范围,输出符合条件的任意一组序列,保证有解。
【思路】对于给定的f[]按照大小排序,大小相等按照下标从小到大排序,ans[]保存最后要输出的答案。很明显,对于f[i]越小且越靠前的值,应该给ans[i]的值应大于下标i小且距离i最近的长度为f[i]-1的元素,并且在区间[l,r]能取的最小值;同时,对于最长上升子序列长度相等的元素来说,下标大的元素的值应该小于等于下标小的值。
【代码如下】
 
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5+10;
struct node{
    int f,l,r,indx;
}p[N];
vector<int>vct[N];
int t,n,ans[N],a[N];

bool cmp(node A, node B){
    if(A.f == B.f) return A.indx < B.indx;
    return A.f < B.f;
}

int main(){
    scanf("%d",&t);
    while(t --){
        scanf("%d",&n);
        for(int i = 0; i <= n+1; i ++) vct[i].clear();
        for(int i = 1; i <= n; i ++) scanf("%d",&p[i].f),p[i].indx = i;
        for(int i = 1; i <= n; i ++) scanf("%d%d",&p[i].l,&p[i].r),a[i]=p[i].r;
        sort(p+1,p+n+1,cmp);
        for(int i = 1; i <= n; i ++){
            int len = p[i].f;
            int l = p[i].l,r=p[i].r;
            int t=-1;
            if(len==1){
                ans[p[i].indx] = l;
                int lena = vct[len].size();
                for(int j = lena-1; j >= 0; j --){
                    int tt = vct[len][j];
                    if(l > ans[tt]) ans[tt]=l;
                    else break;
                }
            }
            else{
                int in = lower_bound(vct[len-1].begin(),vct[len-1].end(),p[i].indx) - vct[len-1].begin()-1;
                int tt = vct[len-1][in];

                if(ans[tt] >= l && ans[tt] < r) t = ans[tt]+1;
                else if(ans[tt] < l) t = l;

                int lena = vct[len].size();
                for(int j = lena-1; j >= 0; j --){
                    int x = vct[len][j];
                    if(ans[x] < t){
                        ans[x] = min(t,a[x]);
                    }
                    else break;
                }
            }
            if(t>0) ans[p[i].indx] = t;
            vct[len].push_back(p[i].indx);
        }
        for(int i = 1; i <= n; i ++){
            if(i>1) printf(" ");
            printf("%d",ans[i]);
        }
        printf("\n");
    }
    return 0;
}

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值