Educational Codeforces Round 134 (Rated for Div. 2)(D:二进制分治)

这篇文章讨论了一种算法,通过二进制位操作(如异或)和排序,解决给定一组整数a和b,如何在不超过30次操作(取异或)下将它们分为两组,使得每组中所有元素的异或值相同。首先进行排序,然后逐层检查二进制位,根据位相同情况合并或细分集合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+10,M=2*N,mod=1e9+7;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
using node=tuple<int,int,int>;
const long long inf=1e18;
 
int n,m,k;
int a[N],b[N];
vector<int> d[N],p[N],dd[N],pp[N];
void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) cin>>b[i];
    for(int i=1;i<=n*5;i++)
    {
        d[i].clear();p[i].clear();
        dd[i].clear();pp[i].clear();
    }
    for(int i=1;i<=n;i++){
        d[1].push_back(i);
        p[1].push_back(i);
    }
    
    int siz=1,ans=0;
    for(int i=30;i>=0;i--)
    {
        bool pd=1;
        for(int j=1;j<=siz;j++)
        {
            int s1=0,s2=0;
            for(int k=0;k<d[j].size();k++)
            {
                int x=a[d[j][k]],y=b[p[j][k]];
                if(x>>i&1) s1++;
                if(y>>i&1) s2++;
            }
            if(s1+s2!=d[j].size())
            {
                pd=0;break;    
            }
        }
        if(pd)
        {
             int sizz=0;
            for(int j=1;j<=siz;j++)
            {
                for(int k=0;k<d[j].size();k++)
                    dd[j].push_back(d[j][k]),pp[j].push_back(p[j][k]);
            }
            for(int j=1;j<=siz;j++) d[j].clear(),p[j].clear();
          
            ans+=1<<i;
            for(int j=1;j<=siz;j++)
            {
                sizz++;
                for(int k=0;k<dd[j].size();k++)
                {
                    int x=a[dd[j][k]];
                    int y=b[pp[j][k]];
                    if(x>>i&1) d[sizz].push_back(dd[j][k]);
                    if(!(y>>i&1)) p[sizz].push_back(pp[j][k]);
                }
                if (d[sizz].size() == 0) sizz --;
                sizz++;
                
                for(int k=0;k<dd[j].size();k++){
                    int x=a[dd[j][k]];
                    if(!(x>>i&1)) d[sizz].push_back(dd[j][k]);
                    int y=b[pp[j][k]];
                    if(y>>i&1) p[sizz].push_back(pp[j][k]);
                }
                if (d[sizz].size() == 0) sizz --;
            }
           
            for(int j=1;j<=siz;j++)
            dd[j].clear(),pp[j].clear();
            swap(siz,sizz);
        }
    }
    cout<<ans<<"\n";
}
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;

    while(t--) solve();
    return 0;
}

因为数最多n个,集合最多有n个不同的集合,遇到分裂的集合的时候,如果大小为0要减一

否则就可能有2^30个不同集合了

基本思路是

0000  111

1111 000

分成两个集合

再从两个不同集合继续细分0 1

这里也可以利用排序,如果不符合条件就把当前位置全部变成相同

且由于异或和大的数对小的数,所以直接sort即可

// LUOGU_RID: 150924569
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,M=2*N,mod=1e9+7;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
using node=tuple<int,int,int>;
const long long inf=1e18;
 
int n,m,k;
int a[N],b[N];
void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) cin>>b[i];
    sort(a+1,a+1+n);
    sort(b+1,b+1+n,greater<>());
    int res=0;
    for(int i=30;i>=0;i--)
    {
        bool f=true;
        for(int j=1;j<=n;j++)
        {
            if((a[j]>>i&1) == (b[j]>>i&1)){
                f=false;break;
            }
        }    
        if(f)  res|=1<<i;
        else
        {
            for(int j=1;j<=n;j++)
            {
                a[j]|=1<<i;
                b[j]|=1<<i;
            }
            sort(a+1,a+1+n);
            sort(b+1,b+1+n,greater<>());
        }
    }
    cout<<res<<"\n";
}
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;

    while(t--) solve();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值