1. 程式人生 > >【NOIP2018模擬賽2018.10.22】cards

【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
*/