題解 隊長快跑
阿新 • • 發佈:2021-07-16
根本就沒想到DP,反倒把問題轉化複雜了
考場暴力思路是在重複點之間連邊,這樣就把問題轉化到了圖上
要求刪儘可能少的點使剩下的點之間沒有邊相連
但這個問題我不會處理……留個坑
其實可以DP
令\(dp[i][j]\)為考慮到位置i,已選的a最小值為j時最大能引爆的水晶個數
轉移很麻煩,但是可以考慮一種優化
- 區間取max轉化為單點取max
我們這裡每次轉移都一定是取某個\(dp[j][k]~dp[j][lim]\)之間的最大值,
而我們每次更新也是取一個\(dp[i][k]~dp[i][lim]\)之間的區間同某個數取max
發現如果當前被修改的區間會對後面的轉移產生貢獻,那\(dp[i][k]\)
所以轉化為單點修改就好了
至於轉移方程,
發現一個點i能從哪個範圍轉移和\(a[i],b[i]\)的大小關係有關
Code:
#include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define N 100010 #define ll long long #define ld long double #define usd unsigned #define ull unsigned long long //#define int long long #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++) char buf[1<<21], *p1=buf, *p2=buf; inline int read() { int ans=0, f=1; char c=getchar(); while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();} while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();} return ans*f; } int n; int a[N], b[N]; namespace force{ int head[N], size, ans, fa[N]; bool vis[N]; struct edge{int to, next;}e[N<<4]; inline void add(int s, int t) {edge* k=&e[++size]; k->to=t; k->next=head[s]; head[s]=size;} struct ele{int cnt, pos;}p[N]; inline bool operator < (ele a, ele b) {return a.cnt<b.cnt;} inline int find(int p) {return fa[p]==p?p:(fa[p]=find(fa[p]));} void dfs(int u, int cnt) { if (u>n) return ; ans = max(ans, cnt); dfs(u+1, cnt); vis[u]=1; for (int i=head[u],v; i; i=e[i].next) { v = e[i].to; if (vis[v]) goto jump; } dfs(u+1, cnt+1); jump: vis[u]=0; } void solve() { for (int i=1; i<=n; ++i) for (int j=i+1; j<=n; ++j) if (a[i]<=b[j]) {add(i, j); add(j, i); vis[i]=1; vis[j]=1; ++p[i].cnt; ++p[j].cnt;} memset(vis, 0, sizeof(bool)*(n+10)); for (int i=1; i<=n; ++i) p[i].pos=i; for (int i=1; i<=n; ++i) fa[i]=i; dfs(1, 0); printf("%d\n", ans); } } namespace task1{ int head[N], size, ans, fa[N]; bool vis[N]; struct edge{int to, next;}e[N<<6]; inline void add(int s, int t) {edge* k=&e[++size]; k->to=t; k->next=head[s]; head[s]=size;} struct ele{int cnt, pos;}p[N]; inline bool operator < (ele a, ele b) {return a.cnt<b.cnt;} inline int find(int p) {return fa[p]==p?p:(fa[p]=find(fa[p]));} void solve() { for (int i=1; i<=n; ++i) for (int j=i+1; j<=n; ++j) if (a[i]<=b[j]) {add(i, j); add(j, i); vis[i]=1; vis[j]=1; ++p[i].cnt; ++p[j].cnt;} memset(vis, 0, sizeof(bool)*(n+10)); for (int i=1; i<=n; ++i) p[i].pos=i; for (int i=1; i<=n; ++i) fa[i]=i; int cnt2=0; while (clock()<=550000) { ++cnt2; int cnt=0; random_shuffle(p+1, p+n+1); sort(p+1, p+n+1); for (int i=1,u; i<=n; ++i) { u=p[i].pos; vis[u]=1; for (int i=head[u],v; i; i=e[i].next) { v = e[i].to; if (vis[v]) {vis[u]=0; goto jump;} } ++cnt; //cout<<"choose "<<u<<endl; jump: ; } ans=max(ans, cnt); } //cout<<"cnt2: "<<cnt2<<endl; printf("%d\n", ans); } } namespace force_n3{ int uni[N<<1], usize; int dp[1010][1010]; void solve() { for (int i=1; i<=n; ++i) uni[i]=a[i]; for (int i=1; i<=n; ++i) uni[n+i]=b[i]; sort(uni+1, uni+n*2+1); usize=unique(uni+1, uni+n*2+1)-uni-1; for (int i=1; i<=n; ++i) a[i]=lower_bound(uni+1, uni+usize+1, a[i])-uni; for (int i=1; i<=n; ++i) b[i]=lower_bound(uni+1, uni+usize+1, b[i])-uni; #ifdef DEBUG cout<<"usize: "<<usize<<endl; cout<<"uni: "; for (int i=1; i<=usize; ++i) cout<<uni[i]<<' '; cout<<endl; cout<<"a: "; for (int i=1; i<=n; ++i) cout<<a[i]<<' '; cout<<endl; cout<<"b: "; for (int i=1; i<=n; ++i) cout<<b[i]<<' '; cout<<endl; cout<<"dp[0]: "; for (int i=1; i<=usize; ++i) cout<<setw(2)<<i<<' '; cout<<endl; #endif for (int i=1; i<=n; ++i) { for (int j=1; j<=usize; ++j) dp[i][j]=dp[i-1][j]; if (a[i]<=b[i]) { int maxn=0; for (int j=b[i]+1; j<=usize; ++j) maxn=max(maxn, dp[i-1][j]); dp[i][a[i]] = max(dp[i][a[i]], maxn+1); } else { int maxn=0; for (int j=a[i]; j<=usize; ++j) maxn=max(maxn, dp[i-1][j]); dp[i][a[i]] = maxn+1; for (int j=b[i]+1; j<a[i]; ++j) dp[i][j]=max(dp[i][j], dp[i-1][j]+1); } #ifdef DEBUG cout<<"dp["<<i<<"]: "; for (int j=1; j<=usize; ++j) cout<<setw(2)<<dp[i][j]<<' '; cout<<endl<<endl; #endif } int ans=0; for (int i=1; i<=usize; ++i) ans=max(ans, dp[n][i]); //cout<<"dp[n]: "; for (int i=1; i<=usize; ++i) cout<<dp[n][i]<<' '; cout<<endl; cout<<ans<<endl; exit(0); } } namespace task{ int uni[N<<1], usize; const int SIZE=N<<3; int tl[SIZE], tr[SIZE], tag[SIZE], maxn[SIZE]; #define tl(p) tl[p] #define tr(p) tr[p] #define tag(p) tag[p] #define maxn(p) maxn[p] #define pushup(p) maxn(p)=max(maxn(p<<1), maxn(p<<1|1)) void spread(int p) { if (!tag(p)) return ; maxn(p<<1)+=tag(p); tag(p<<1)+=tag(p); maxn(p<<1|1)+=tag(p); tag(p<<1|1)+=tag(p); tag(p)=0; } void build(int p, int l, int r) { tl(p)=l; tr(p)=r; if (l>=r) return ; int mid=(l+r)>>1; build(p<<1, l, mid); build(p<<1|1, mid+1, r); } void upd(int p, int pos, int dat) { if (tl(p)==tr(p)) {maxn(p)=max(maxn(p), dat); return ;} spread(p); int mid=(tl(p)+tr(p))>>1; if (pos<=mid) upd(p<<1, pos, dat); else upd(p<<1|1, pos, dat); pushup(p); } void upd(int p, int l, int r, int dat) { if (l<=tl(p)&&r>=tr(p)) {maxn(p)+=dat; tag(p)+=dat; return ;} spread(p); int mid=(tl(p)+tr(p))>>1; if (l<=mid) upd(p<<1, l, r, dat); if (r>mid) upd(p<<1|1, l, r, dat); pushup(p); } int query(int p, int l, int r) { if (l<=tl(p)&&r>=tr(p)) return maxn(p); spread(p); int mid=(tl(p)+tr(p))>>1, ans=0; if (l<=mid) ans=max(ans, query(p<<1, l, r)); if (r>mid) ans=max(ans, query(p<<1|1, l, r)); return ans; } void solve() { for (int i=1; i<=n; ++i) uni[i]=a[i]; for (int i=1; i<=n; ++i) uni[n+i]=b[i]; sort(uni+1, uni+n*2+1); usize=unique(uni+1, uni+n*2+1)-uni-1; for (int i=1; i<=n; ++i) a[i]=lower_bound(uni+1, uni+usize+1, a[i])-uni; for (int i=1; i<=n; ++i) b[i]=lower_bound(uni+1, uni+usize+1, b[i])-uni; build(1, 1, usize); for (int i=1; i<=n; ++i) { if (a[i]<=b[i]) { upd(1, a[i], query(1, b[i]+1, usize)+1); } else { upd(1, a[i], query(1, a[i], usize)+1); upd(1, b[i]+1, a[i]-1, 1); } #ifdef DEBUG cout<<"dp["<<i<<"]: "; for (int j=1; j<=usize; ++j) cout<<setw(2)<<query(1, j, j)<<' '; cout<<endl<<endl; #endif } printf("%d\n", query(1, 1, usize)); exit(0); } } signed main() { #ifdef DEBUG freopen("1.in", "r", stdin); #endif bool flag=1; n=read(); for (int i=1; i<=n; ++i) {a[i]=read(); b[i]=read(); if (a[i]>2||b[i]>2) flag=0;} task::solve(); if (n<=10) force::solve(); else if (flag) { int maxn=a[1]; for (int i=2; i<=n; ++i) { if (b[i]<maxn) {puts("2"); return 0;} maxn=max(maxn, a[i]); } puts("1"); return 0; } else task1::solve(); return 0; }