【NOIP2018模擬賽2018.10.22】cards
阿新 • • 發佈:2018-11-06
這道題十分陰險啊。。
一般來說看到這道題都會選擇打一個最長上升子序列的模板吧(比較時就比較三個引數)。。。。
但你可以看到,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 */