题解 合成小丹

传送门

首先给定的操作是按为或后右移一位
那么均为 2 的幂次减一的部分分可以按最高位排序后贪心

然后发现这些数任意的时候再按位贪心就假了
于是找性质发现 \(\frac{x|y}{2}=\frac{x}{2}|\frac{y}{2}\)
于是拆开考虑每个数没操作了多少次
\(ans\) 写成 \(\frac{x_0}{2^{d_0}}|\frac{x_1}{2^{d_1}}| \cdots | \frac{x_n}{2^{d_n}}\)
发现一组 \(\{d_i\}\) 合法的条件为 \(\sum\limits_{i=1}^n\frac{1}{2^{d_i}}\geqslant 1\)
大于的情况可以合并并删除一些没用的数
于是令 \(dp_{i, j}\) 为考虑了前 \(i\) 个数,它们右移后取或结果为 \(j\) 时的 \(\sum\limits_{i=1}^n\frac{1}{2^{d_i}}\) 最大值
于是可以 DP,复杂度 \(O(Tn2^nw)\)

但是发现过不去,需要优化
发现 \(d_i\) 越小越优
尝试按位确定 ans
ans 这一位为 0 的条件是存在一组 \(\{d_i\}\) 使得每个 \(x\) 右移后与上 ans 已经确定的部分仍等于这个数,枚举即可
复杂度 \(O(Tnw^2)\)

image
关于为什么是右移 \(t\) 位:
考虑 \(a_i\) 在第 \(j\) 位为 1,此时钦定第 \(t\) 位为 0
那么右移 \(j-t\) 位是不合法的,发现恰好就是 \(a_i>>t\)
复杂度 \(O(Tnw)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define N 100010
#define ll long long
#define pb push_back
#define int long long
#define int128 __int128

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 n, w;
int a[N];

// namespace force{
// 	ll ans;
// 	void dfs(int u, vector<int> s) {
// 		// cout<<"dfs: "<<u<<' '; for (auto it:s) cout<<it<<' '; cout<<endl;
// 		if (!s.size()) return ;
// 		if (s.size()==1) {ans=min(ans, s[0]); return ;}
// 		if (u<0) {for (auto it:s) ans=min(ans, it); return ;}
// 		vector<int> tem, t2, other;
// 		for (auto it:s)
// 			if (it&(1ll<<u)) tem.pb(it);
// 			else other.pb(it);
		
// 		if (!tem.size()) dfs(u-1, s);
// 		else {
// 			sort(tem.begin(), tem.end());
// 			do {
// 				t2.clear();
// 				for (int i=1; i<tem.size(); i+=2) t2.pb((tem[i]|tem[i-1])>>1);
// 				for (auto it:other) t2.pb(it);
// 				dfs(u-1, t2);
// 			} while (next_permutation(tem.begin(), tem.end()));
// 		}
// 		// if (tem.size()&1) {
// 		// 	for (int i=0; i<tem.size(); ++i) {
// 		// 		t2.clear();
// 		// 		for (int j=1; j<i; j+=2) t2.pb((tem[j]|tem[j-1])>>1);
// 		// 		for (int j=i+1; j<tem.size(); j+=2) t2.pb((tem[j]|tem[j+1])>>1);
// 		// 		for (auto it:other) t2.pb(it);
// 		// 		dfs(u-1, t2);
// 		// 	}
// 		// }
// 		// else 
// 		// else {
// 		// 	t2.clear();
// 		// 	for (int j=1; j<tem.size(); j+=2) t2.pb((tem[j]|tem[j-1])>>1);
// 		// 	for (auto it:other) t2.pb(it);
// 		// 	dfs(u-1, t2);
// 		// }
// 	}
// 	void solve() {
// 		ans=INF;
// 		vector<int> tem;
// 		for (int i=1; i<=n; ++i) tem.pb(a[i]);
// 		dfs(62, tem);
// 		cout<<ans<<endl;
// 	}
// }

namespace force{
	ll ans;
	map<vector<int>, bool> mp;
	void dfs(vector<int> s) {
		sort(s.begin(), s.end());
		for (auto& it:s) ans=min(ans, it);
		if (s.size()<=1) return ;
		if (mp.find(s)!=mp.end()) return ;
		vector<int> t2;
		for (int i=0; i<s.size(); ++i)
			for (int j=i+1; j<s.size(); ++j) {
				t2.clear();
				for (int k=0; k<s.size(); ++k)
					if (k!=i && k!=j) t2.pb(s[k]);
				t2.pb((s[i]|s[j])>>1);
				dfs(t2);
			}
		mp[s]=1;
	}
	void solve() {
		ans=INF;
		mp.clear();
		vector<int> tem;
		for (int i=1; i<=n; ++i) tem.pb(a[i]);
		dfs(tem);
		cout<<ans<<endl;
	}
}

namespace task1{
	ll ans;
	int nll[1000], *s;
	void solve() {
		ans=INF;
		s=nll+100;
		for (int i=-1; i<=65; ++i) s[i]=0;
		for (int i=1; i<=n; ++i) if (__builtin_popcount(a[i]+1)>1) {puts("0"); return ;}
		for (int i=1; i<=n; ++i) {
			if (a[i]==0) {cout<<0<<endl; return ;}
			for (int j=63; ~j; --j)
				if (a[i]&(1ll<<j)) {++s[j]; break;}
		}
		// cout<<"s: "; for (int i=0; i<=10; ++i) cout<<s[i]<<' '; cout<<endl;
		for (int i=63; ~i; --i) {
			if (s[i]) ans=min(ans, (1ll<<(i+1))-1);
			s[i-1]+=s[i]/2;
		}
		if (s[-1]) ans=0;
		cout<<ans<<endl;
	}
}

namespace task2{
	ll ans;
	const int128 base=1ll<<62;
	void solve() {
		ans=0;
		for (int i=1; i<=w; ++i) {
			int128 sum=0;
			ans=ans<<1;
			for (int j=1; j<=n; ++j) {
				int128 tem=base; int t=a[j]>>(w-i);
				while ((t&ans)!=t) t>>=1, tem>>=1;
				sum+=tem;
			}
			ans=ans|(sum<base);
		}
		printf("%lld\n", ans);
	}
}

namespace task{
	ll b[N], ans;
	const int128 base=1ll<<62;
	void solve() {
		ans=0;
		memset(b, 0, sizeof(b));
		for (int i=w-1; ~i; --i) {
			// cout<<"i: "<<i<<endl;
			int128 sum=0;
			for (int j=1; j<=n; ++j) {
				int128 tem=base; int t=(a[j]>>i);
				// while ((t&ans)!=t) t>>=1, tem>>=1;
				int len=__builtin_ffs(~b[j])-1;
				t>>=len, tem>>=len;
				// int kkk=b[j]>>i;
				// while (kkk&1) t>>=1, tem>>=1, kkk>>=1;
				while (((t<<i)&ans)!=(t<<i)) t>>=1, tem>>=1;
				sum+=tem;
			}
			ans=ans|(1ll*(sum<base)<<i);
			if (sum>=base) for (int j=1; j<=n; ++j) b[j]|=a[j]>>i; //, cout<<"b["<<j<<"]="<<bitset<5>(b[j])<<endl;
		}
		printf("%lld\n", ans);
	}
}

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

	int T=read();
	while (T--) {
		n=read(); w=read();
		for (int i=1; i<=n; ++i) a[i]=read();
		// if (n<=20) force::solve();
		// else task1::solve();
		task::solve();
	}

	return 0;
}
posted @ 2022-01-24 10:27  Administrator-09  阅读(1)  评论(0编辑  收藏  举报