题解 史莱姆B

传送门

  • 有序数列中临项异或和最小值为数列中所有二元组异或和最小值
  • \(a\oplus(a+b)\geqslant b\),证明考虑是否进位即可
    变形成 \(a\leqslant b\)\(b\oplus a\geqslant b-a\) 也许可以作为切入点

考虑 sub2 怎么写
\(t=\min{\{s_{i+1}-s_i\}}\),那么 \(w\geqslant t\) 时答案为 t
否则 \(t\leqslant \dfrac{2^V}{|S|}\),枚举答案的复杂度是 \(O(2^V)\)
那么 sub3 可以只在集合大小发生变化时重算,复杂度调和级数知是 \(O(V2^V)\)

然后正解:
对于一对相邻 \((i, j)\),有用的 \(x\) 只有 \(O(V)\) 个,且一定是使 \(i+x\)\(j+x\) 的后 \(k\in[0, V]\) 位为 0
打表应该是一个比较好的发现方法
证明的话考虑 \(i+x\)\(k\) 位为 0,让 \(x\) 继续变大
那么答案想更优的话 \(j\) 一定产生了向第 \(k+1\) 位的进位
考虑对 \(y\) 操作的最低位
若操作了某一位,则一定会一直操作使其一直进到第 \(k+1\)
操作最低为 1 位一定更优
那么这样 \(j+x\)\(k+1\) 位就都为 0 了

于是用 set 对所有二元组 \((x, (i+x)\oplus(j+x))\) 维护单调栈即可
复杂度 \(O(n\log n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define ll long long
#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
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 v, n;

namespace force{
	int sta[N], top;
	void solve() {
		for (int i=1,op,w; i<=n; ++i) {
			op=read(); w=read();
			if (op==1) sta[++top]=w;
			else {
				int ans=INF;
				for (int x=0; x<=w; ++x)
					for (int i=1; i<=top; ++i)
						for (int j=i+1; j<=top; ++j)
							ans=min(ans, (x+sta[i])^(x+sta[j]));
				printf("%d\n", ans);
			}
		}
	}
}

namespace task{
	set<int> s;
	set<pair<int, int>> ans;
	void ins(int i, int j, int x) {
		int val=(i+x)^(j+x);
		for (auto it=ans.lower_bound({x, val}); it!=ans.end()&&it->sec>=val; it=ans.erase(it)) ;
		auto pre=ans.lower_bound({x, val});
		if (pre!=ans.begin() && (--pre)->sec<=val) return ;
		ans.insert({x, val});
	}
	void add(int i, int j) {
		int lim=1;
		ins(i, j, 0);
		for (int k=0,x; k<=v; ++k,lim<<=1) {
			x=lim-(i&(lim-1));
			ins(i, j, x);
			x=lim-(j&(lim-1));
			ins(i, j, x);
		}
	}
	void solve() {
		for (int i=1,op,w; i<=n; ++i) {
			// cout<<"i: "<<i<<endl;
			op=read(); w=read();
			if (op==1) {
				auto it=s.lower_bound(w);
				if (it!=s.end()) add(w, *it);
				if (it!=s.begin()) add(w, *(--it));
				s.insert(w);
			}
			else printf("%lld\n", (--ans.upper_bound({w, INF}))->sec);
			// cout<<"ans: "; for (auto it:ans) cout<<"("<<it.fir<<','<<it.sec<<") "; cout<<endl;
		}
	}
}

signed main()
{
	freopen("b.in", "r", stdin);
	freopen("b.out", "w", stdout);

	v=read(); n=read();
	// force::solve();	
	task::solve();

	return 0;
}
posted @ 2022-04-12 16:46  Administrator-09  阅读(3)  评论(0编辑  收藏  举报