【NOIP2018模拟赛2018.10.22】cards

 这道题十分阴险啊。。

一般来说看到这道题都会选择打一个最长上升子序列的模板吧(比较时就比较三个参数)。。。。

但你可以看到,5,6,7,8四个点m达到了1e6的规模,那么n^2的复杂的肯定是过不了的。

又可以惊奇的发现,1~8个点的z都为0

于是经过仔(can)细(kao)思(ti)考(jie)后,1~8个点发现咱可以用树状数组维护DP转移,使其复杂度降到O(nlogn)。

而剩下俩个点 m <= 1e3直接 pi<pj 就连一条 i->j 的边 spfa跑最长链就可以了。

树状数组用得很巧妙,首先z已经为0了,不管它,将x从小到大把卡牌排一遍,然后以y为准进行转移。

那么可以知道,当yi > yj 时,yi处的 f[i] 可以由 f[j] 转移而来,于是我们把y值当做序号,小的放在树状数组前面,大的放在树状数组后面,依次ask并updata求最大值就好了(。。表达不太清楚请看代码)

代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 5;
#define ll long long
#define pt putchar
#define ex pt('\n')
#define ko pt(' ')
int n;
int ans = 1;
bool z0 = 1;
int head[MAXN<<1],cnt = 0;
int dis[MAXN];
struct edge
{
	int next,to;
}e[MAXN<<1];
void add(int u,int v)
{
	e[++cnt].next = head[u]; e[cnt].to = v; head[u] = cnt;
}
void in(int &x)
{
	int num = 0,f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {num = (num<<3) + (num<<1) + (ch-'0'); ch = getchar();}
	x = num*f;
}
void out(int x)
{
	if(x < 0) x = -x,pt('-');
	if(x > 9) out(x/10);
	pt(x%10 + '0');
}
struct card
{
	int x,y,z;
	bool operator < (const card one) const
	{
		if(x != one.x) return x < one.x;
		return y < one.y;
	}
}c[MAXN];
ll f[MAXN];

int lowbit(int x) {return x&-x;}

void updata(int x,ll v)
{
	while(x < MAXN)
	{
		f[x] = max(v,f[x]);
		x += lowbit(x);
	}
}

int ask(int x)
{
	ll res = 0;
	while(x)
	{
		res = max(f[x],res);
		x -= lowbit(x);
	}
	return res;
}

inline void init()
{
	in(n);
	for(int i = 1;i <= n;i++)
	{
		in(c[i].x),in(c[i].y),in(c[i].z);
		if(c[i].z != 0) z0 = 0;
	}
		
}

void work1()
{
	sort(c+1,c+n+1);
	for(int i = 1;i <= n;i++)
	{
		int tmp = ask(c[i].y) + 1;
		ans = max(ans,tmp);
		updata(c[i].y,tmp); 
	}
}

bool check(int i,int j)
{
	if(c[i].x <= c[j].x && c[i].y <= c[j].y && c[i].z <= c[j].z) return 1;
	return 0;
}

int q[MAXN<<1];
bool vis[MAXN];
void spfa(int st)
{
	int h = 0,t = 0;
	memset(vis,0,sizeof vis);
	q[++t] = st; vis[st] = 1;
	while(h < t)
	{
		int x = q[++h];
		for(int i = head[x];i;i = e[i].next)
		{
			int to = e[i].to;
			if(vis[to]) continue;
			if(dis[x] + 1 > dis[to])
			{
				vis[to] = 1;
				dis[to] = dis[x] + 1;
				q[++t] = to;
			}
		}
	}
	for(int i = 1;i <= n;i++) ans = max(ans,dis[i]);
}

void work2()
{
	for(int i = 1;i <= n;i++)
		for(int j = 1;j <= n;j++)
			if(check(i,j) && i != j) add(i,j);
	for(int i = 1;i <= n;i++) spfa(i);
	ans++;
}

int main()
{
	init();
	if(c[1].y == 0) {cout << n; return 0;}
	if(z0) work1();
	else work2(); 
	out(ans);
	return 0;
}
/*
4
5 7 6
1 3 4
5 4 4
3 3 8
*/

猜你喜欢

转载自blog.csdn.net/chang_yl/article/details/83278790