题解 队长快跑

传送门

根本就没想到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]\)一定会造成贡献
所以转化为单点修改就好了
至于转移方程,这个我真的不会DP啊啊啊
发现一个点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;
}
posted @ 2021-07-16 17:03  Administrator-09  阅读(12)  评论(0编辑  收藏  举报