题解 队长快跑
根本就没想到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;
}