题解 合成小丹
首先给定的操作是按为或后右移一位
那么均为 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)\)
关于为什么是右移 \(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;
}