ZOJ 4028 && 15th浙江省省赛E. LIS(神奇贪心)

版权声明:本文为博主原创文章,你们可以随便转载 https://blog.csdn.net/Jaihk662/article/details/83188401

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4028

题意:

有一个长度为n的序列A,你不知道这个序列的中每个元素是什么,只知道

  1. F[x]表示以第x个元素结尾的最长上升子序列长度(绝对单调)
  2. 第x个数的取值范围为L[x]到R[x](闭区间)

求恢复序列A,只要满足条件就可以了,保证有解,输出任意一种

思路:

网上题解好像都是差分约束,还要用到SPFA,其实只要贪心就行了

稍加分析可以得出:对于第x个数字a[x],只需要满足最多两个条件即可

  1. a[x] ≤ a[y](其中y是离x最近的满足F[y] = F[x]的位置,y<x,可能不存在)
  2. a[x] > a[k](其中k是离x最近的满足F[k]+1 = F[x],k<x,可能不存在)

然后再仔细分析一波你会发现,这些不等式可以连成一条有向无环图,而对于有向无环不等式关系,很明显可以从入度为0的点开始直接贪心,每次只要填入的数尽可能小即可!!

具体贪心顺序是:以F[x]从小到大为第一顺序,相同F[x]以位置从后往前为第二顺序填数 

复杂度线性,具体过程如代码

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
#define LL long long
#define mod 1000000007
int a[100005], L[100005], last[100005], ans[100005];
vector<int> G[100005];
typedef struct Res
{
	int l;
	int r;
}Res;
Res s[100005];
int main(void)
{
	int T, n, i, j, now, loc;
	scanf("%d", &T);
	while(T--)
	{
		scanf("%d", &n);
		for(i=1;i<=n;i++)
		{
			scanf("%d", &a[i]);
			G[i].clear();
		}
		for(i=1;i<=n;i++)
			scanf("%d%d", &s[i].l, &s[i].r);
		for(i=1;i<=n;i++)
		{
			last[a[i]] = i;
			L[i] = last[a[i]-1];
		}
		for(i=n;i>=1;i--)
			G[a[i]].push_back(i);
		for(i=1;i<=n;i++)
		{
			for(j=0;j<G[i].size();j++)
			{
				loc = G[i][j];
				if(j==0)
				{
					if(i==1)
						now = s[loc].l;
					else
						now = max(ans[L[loc]]+1, s[loc].l);
				}
				else
				{
					if(i==1)
						now = max(s[loc].l, now);
					else
						now = max(ans[L[loc]]+1, max(s[loc].l, now));
				}
				ans[loc] = now;
			}
		}
		printf("%d", ans[1]);
		for(i=2;i<=n;i++)
			printf(" %d", ans[i]);
		puts("");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Jaihk662/article/details/83188401