开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第18天,点击查看活动详情
D-补天裂_牛客练习赛107 (nowcoder.com)
题意:给出一个长度为n的数组,可以选择a[i]和a[j]使得u=a[i]&a[j],v=a[i]|a[j],然后a[i]=u,a[j]=v,可以进行任意次这样的操作使得最后数组的字典序最小
思路:可以发现无论怎样操作数组中1和0的总数是不会变的,所以把1都给最后的几个数就可以了,先统计出每一个二进制位上1的个数,然后从n到1开始给每个数赋值,假如这一位的1还没有花完就a[i]+=(1<<j),bit[j]--,然后继续向下看
#include<bits/stdc++.h>
//#pragma-GCC-optimize("-Ofast");
#define ll long long
#define int long long
#define lowbit(x) ((x)&(-x))
#define endl '\n'
using namespace std;
const ll mod=998244353;
const ll inf=1e18;
const double pi=acos(-1);
const int N=1e6+100;
ll qpow(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a){return qpow(a,mod-2);}
int t,n,a[N],bit[N];
signed main()
{
// ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
// cin>>t;
// while(t--)
// {
// cin>>n;
// for(int i=1;i<=n;i++) cin>>b[i],a[i]=i;
// int ans=inf;
// do
// {
// int res=0,res1=0,minn=inf;
// for(int i=1;i<=n;i++)
// {
// if(minn>a[i])
// {
// minn=a[i];res++;
// }
// c[i]=a[b[i]];
// }
// minn=inf;
// for(int i=1;i<=n;i++)
// {
// if(minn>c[i])
// {
// minn=c[i];res1++;
// }
// }
// if(max(res1,res)<ans)
// {
// ans=max(res1,res);
// for(int i=1;i<=n;i++) d[i]=a[i];
// }
// }while(next_permutation(a+1,a+n+1));
// cout<<ans<<endl;
// for(int i=1;i<=n;i++) cout<<d[i]<<" ";
// }
// cin>>t;
// while(t--)
// {
// cin>>n;
// for(int i=0;i<=32;i++) bit[i]=0;
// for(int i=1;i<=n;i++)
// {
// int x;cin>>x;
// for(int j=0;j<=32;j++)
// {
// if((x>>j)&1) bit[j]++;
// }
// }
// for(int i=n;i>=1;i--)
// {
// a[i]=0;
// for(int j=0;j<=32;j++)
// {
// if(bit[j])
// {
// a[i]+=(1LL<<j);
// bit[j]--;
// }
// }
// }
// for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
// }
cin>>t;
while(t--)
{
cin>>n;
for(int i=0;i<=32;i++) bit[i]=0;
for(int i=1;i<=n;i++)
{
int x;cin>>x;
for(int j=0;j<=32;j++)
{
if((x>>j)&1) bit[j]++;
}
}
for(int i=n;i>=1;i--)
{
a[i]=0;
for(int j=0;j<=32;j++)
{
if(bit[j])
{
a[i]+=(1LL<<j);
bit[j]--;
}
}
}
for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
}
return 0;
}