【LIS】【递推】Gym - 101246H - ``North-East''

x坐标排序,y坐标当权值,同一个x坐标的,y从大到小排。

求f(i)表示以i结尾的LIS以后,从后向前枚举,不断更新一个max数组,max(i)代表最长上升子序列为i时,当前的 结尾的最大值是多少。

一个元素可能在LIS里面,则说明存在一个j>i,f(j)=f(i)+1,且a(j)>a(i),就查询一下max(f(i)+1)是否大于a(i)即可。如果可行的话,再用该值更新max数组。

一定在LIS里面的就是i可能在LIS里面,并且f(i)只出现了一次的。

队友的代码(↓)

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lowbit(x) ((x)&-(x))
using namespace std;
struct node{
	int x,y,id;
}a[100005];
bool cmp(node a,node b)
{
	return a.x==b.x?a.y>b.y:a.x<b.x;
}
int Ans1[100005],Ans2[100005],f[100005],g[100005],vis[100005],n,ans1num,ans2num,s[100005],ans,ls[100005];
bool cmp2(int a,int b)
{
	return f[a]<f[b];
}
bool ans1[100005];
void add(int p,int x)
{
	p=lower_bound(ls+1,ls+n+1,p)-ls;
	for(;p<=n;p+=lowbit(p))
	{
		s[p]=max(s[p],x);
	}
}
int get(int p)
{
	p=lower_bound(ls+1,ls+n+1,p)-ls-1;
	int nowans=0;
	for(;p;p-=lowbit(p))
	{
		nowans=max(nowans,s[p]);
	}
	return nowans;
}
int main()
{
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
	{
		scanf("%d%d",&a[i].x,&a[i].y);
		a[i].id=i;
		ls[i]=a[i].y;
	}
	sort(ls+1,ls+n+1);
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;++i)
	{
		f[i]=get(a[i].y)+1;
		add(a[i].y,f[i]);
		ans=max(ans,f[i]);
	}
	for(int i=n;i;--i)
	{
		if(f[i]==ans||(vis[f[i]+1]&&a[i].y<g[f[i]+1]))
		{
			ans1[i]=1;
			if(vis[f[i]]==0)
			{
				g[f[i]]=a[i].y;
				vis[f[i]]=1;
			}
			else
			{
				g[f[i]]=max(g[f[i]],a[i].y);
			}
		}
	}
	for(int i=1;i<=n;++i)
	if(ans1[i])
	{
		Ans1[++ans1num]=i;
	}
	sort(Ans1+1,Ans1+ans1num,cmp2);
	for(int i=1;i<=ans1num;++i)
	{
		if(f[Ans1[i]]!=f[Ans1[i-1]]&&f[Ans1[i]]!=f[Ans1[i+1]])
		{
			Ans2[++ans2num]=a[Ans1[i]].id;
		}
	}
	for(int i=1;i<=ans1num;++i)
	Ans1[i]=a[Ans1[i]].id;
	sort(Ans1+1,Ans1+ans1num+1);
	sort(Ans2+1,Ans2+ans2num+1);

	printf("%d ",ans1num);
	for(int i=1;i<ans1num;++i)
		printf("%d ",Ans1[i]);
	if(ans1num) printf("%d\n",Ans1[ans1num]);
	printf("%d ",ans2num);
	for(int i=1;i<ans2num;++i)
		printf("%d ",Ans2[i]);
	if(ans2num)printf("%d\n",Ans2[ans2num]);
	return 0;
}

【LIS】【递推】Gym - 101246H - ``North-East''

时间: 2024-12-06 13:54:26

【LIS】【递推】Gym - 101246H - ``North-East''的相关文章

Gym 101246H ``North-East&#39;&#39;(LIS)

http://codeforces.com/gym/101246/problem/H 题意: 给出n个点的坐标,现在有一个乐队,他可以从任一点出发,但是只能往右上方走(包括右方和上方),要经过尽量多的点.输出它可能经过的点和一定会经过的点. 思路: 分析一下第一个案例,在坐标图上画出来,可以发现,他最多可以经过4个点,有两种方法可以走. 观察一下,就可以发现这道题目就是要我们求一个LIS. 首先,对输入数据排一下顺序,x小的排前,相等时则将y大的优先排前面. 用二分法求LIS,这样在d数组中就可

【递推】【DFS】【枚举】Gym - 101246C - Explode &#39;Em All

网格里放了一些石块,一个炸弹能炸开其所在的行和列.问炸光石块至少要几个炸弹. 枚举不炸开的行数,则可以得出还要炸开几列. 为了不让复杂度爆炸,需要两个优化. 先是递推预处理出f(i)表示i的二进制位中1的个数,f(i)=f(i-2^k)+1,k是可以推算出来的. 还要DFS枚举不炸开的行数,防止重复访问.(类似容斥的时候的写法) #include<cstdio> #include<algorithm> using namespace std; int n,m,f[1<<

【66测试20161115】【树】【DP_LIS】【SPFA】【同余最短路】【递推】【矩阵快速幂】

还有3天,今天考试又崩了.状态还没有调整过来... 第一题:小L的二叉树 勤奋又善于思考的小L接触了信息学竞赛,开始的学习十分顺利.但是,小L对数据结构的掌握实在十分渣渣.所以,小L当时卡在了二叉树. 在计算机科学中,二叉树是每个结点最多有两个子结点的有序树.通常子结点被称作“左孩子”和“右孩子”.二叉树被用作二叉搜索树和二叉堆.随后他又和他人讨论起了二叉搜索树.什么是二叉搜索树呢?二叉搜索树首先是一棵二叉树.设key[p]表示结点p上的数值.对于其中的每个结点p,若其存在左孩子lch,则key

Code Force 429B Working out【递推dp】

Summer is coming! It's time for Iahub and Iahubina to work out, as they both want to look hot at the beach. The gym where they go is a matrix a with n lines and mcolumns. Let number a[i][j] represents the calories burned by performing workout at the

hdu 1207 汉诺塔II (DP+递推)

汉诺塔II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4529    Accepted Submission(s): 2231 Problem Description 经典的汉诺塔问题经常作为一个递归的经典例题存在.可能有人并不知道汉诺塔问题的典故.汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从下往

hdu 1267 递推

下沙的沙子有几粒? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4326    Accepted Submission(s): 2268 Problem Description 2005年11月份,我们学校参加了ACM/ICPC 亚洲赛区成都站的比赛,在这里,我们获得了历史性的突破,尽管只是一枚铜牌,但获奖那一刻的激动,也许将永远铭刻

hdu 2067(递推或卡特兰数【待补充】)

//解法一:递推#include<iostream> using namespace std; long long d[36][36]; int main() { for(int i=1;i<=35;i++) { d[0][i]=1; } for(int i=1;i<=35;i++) for(int j=i;j<=35;j++) { if(i==j) d[i][j]=d[i-1][j]; else d[i][j]=d[i-1][j]+d[i][j-1]; } int n; i

NPU 2015年陕西省程序设计竞赛网络预赛(正式赛)F题 和谐的比赛(递推 ||卡特兰数(转化成01字符串))

Description 今天西工大举办了一场比赛总共有m+n人,但是有m人比较懒没带电脑,另外的n个人带了电脑.不幸的是,今天机房的电脑全坏了只能用带的电脑,一台电脑最多两人公用,确保n>=m.但是大家来的时间不同,随机次序来机房,带电脑的人直接准备比赛而没带电脑的人需要向带电脑并还没和别人公用的人求助(当然会答应).但是,如果不存在带电脑并还没和别人公用的人,那他就要等了,等是很让人头疼的,这就不和谐了,当然假如没有这样的情况发生比赛是很和谐的. Input 输入多组数据,每组数据只有一行m(

矩阵经典题目七:Warcraft III 守望者的烦恼(矩阵加速递推)

https://www.vijos.org/p/1067 很容易推出递推式f[n] = f[n-1]+f[n-2]+......+f[n-k]. 构造矩阵的方法:构造一个k*k的矩阵,其中右上角的(k-1)*(k-1)的矩阵是单位矩阵,第k行的每个数分别对应f[n-1],f[n-2],,f[n-k]的系数.然后构造一个k*1的矩阵,它的第i行代表f[i],是经过直接递推得到的.设ans[][]是第一个矩阵的n-k次幂乘上第二个矩阵,f[n]就是ans[k][1]. 注意:用__int64 #in