算法-试填法
1、试填法
D-Digital Pairing_牛客周赛 Round 112
算法思路
核心思想:贪心 + 按位处理
从高位到低位贪心:从最高位(第32位)开始,依次检查每个位能否设置为1
位可行性检查:对于当前位,检查有多少个数字在该位上为1且满足之前高位的要求
逐步筛选:如果满足条件的数字足够组成两组(每组n个),则将该位加入答案,并只保留这些满足条件的数字进行后续处理
最终结果:所有能够设置的位组合起来就是最大总和谐度
关键点
优先保证高位为1,因为高位对数值的影响更大
通过
vis
数组来跟踪哪些数字满足当前所有已选位的要求每次成功设置一个位后,只考虑那些在该位为1且满足之前所有条件的数字
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=4e5+10;
void solve(){ll n;cin>>n;vector<ll> a(n*2+1);// 读入2n个数字for(ll i=1;i<=n*2;i++){cin>>a[i];} ll ans=0;// vis数组:标记哪些数字当前还满足条件(初始都满足)vector<ll> vis(n*2+1,1);// 从高位到低位贪心(32位到0位)for(ll bit=32;bit>=0;bit--){vector<ll> v; // 存储当前位为1的数字索引vector<ll> nvis(n*2+1,0); // 新的vis数组// 遍历所有数字,检查当前位是否为1且满足之前条件for(ll i=1;i<=n*2;i++){if(!vis[i]) continue; // 跳过不满足之前条件的数字// 检查数字a[i]的第bit位是否为1if(a[i]>>bit & 1){v.emplace_back(i); // 记录满足条件的数字索引}} // 如果满足条件的数字足够组成两组(每组需要n个)if(v.size()>=n){// 设置答案的当前位为1ans |= (1LL << bit); // 更新vis数组:只保留在当前位为1的数字for(auto & i:v){nvis[i]=1;}vis = nvis; // 更新条件筛选}// 如果不够,保持当前vis不变,继续检查下一位}cout<<ans<<endl;
}
int main(){ll t;cin>>t;while(t--){solve();}return 0;
}