首页 > 其他分享 >CF1721D(Edu134Div2-D)

CF1721D(Edu134Div2-D)

时间:2022-08-28 10:23:06浏览次数:95  
标签:std CF1721D 高位 int long 100005 分裂 Edu134Div2

原题链接

一个显然的结论是,从高位道低位考虑答案在这一位是否可以是1,那么如果一个高位可以为1,那么一定不会为了其他低位而把它变成0。另一个结论是:如果一个高位不能变成1,那么这个高位不会对后续答案的考查产生任何限制。

接下来思考对于一个位,什么时候答案在这位可以变成1。注意到对于第1高位,统计A数组中这一位0的个数,考虑B数组中这一位1的个数,如果两个数相同,那么第一高位可以是1。

随后,我们考察它对于后续的位会产生什么限制。当我们确定第1高位一定是1以后,所有的第一高位是0的Ai,一定只会和第一高位是1的Bj组合在一起;同时只要满足前一条,这种组合就是任意的。除此之外,我们知道上述限制中,Ai和Bj的总个数相同。所以一个策略是:我们考虑按照第1高位把原数列分段,接下来每一位的匹配都发生在某一段内部。具体地,对于A在统计有多少最高位是0的过程中,把所有最高位是0的Ai交换到当前段的开头(对于第1高位,这就是整个A的开头),对于B也是如此。

注意,这一步只不过进行预处理,还没有把当前段分裂开。这是因为,对于当前考查的位,必须把每一段都考察完,我们才能确定每一段是否都满足“A中0等于B中1”的性质,也即答案的当前位可否为1。

接下来,我们进行如下处理。如果上述结论是可以为1,那么我们对于刚才考察过程中记录下来的每一段的“分裂点”,也就是在这一段内部,满足“前面都是A为0、B为1,后面都不是”的这个点,把它同步到所有分裂点的集合中。而如果结论是不是,我们就直接什么也不做,虽然我们在考察过程中,已经把AB数组进行了分类,但是这种分类只是段内的重新排序,一个显然结论是,这种重新排序不会影响答案(就像A或B输入时的顺序不影响排序一样,有意义的只是集合而不是顺序)。所以只要不同步分裂点就等于啥也没做。

我的代码以下供参考。其中lir标记一个点是否为分裂点,nir标记一个点是否是当前这位考察过程中处理出的潜在的分裂点。

#include <bits/stdc++.h>

using std::vector;
using std::max; using std::min;

typedef long long LL;
typedef unsigned long long UL;

int a[100005], b[100005];
int lir[100005], nir[100005];

int main(void)
{
    int tsk; scanf("%d", &tsk);
    while (tsk--)
    {
        int n; scanf("%d", &n);
        for (int i = 1; i <= n; ++i)
        {
            scanf("%d", &a[i]);
        }
        for (int i = 1; i <= n; ++i)
        {
            scanf("%d", &b[i]);
        }

        for (int i = 1; i <= n; ++i)
        {
            lir[i] = 0;
        }

        int ans = 0;
        for (int d = 29; d >= 0; --d)
        {
            for (int i = 1; i <= n; ++i)
            {
                nir[i] = 0;
            }

            int t1 = 1, t2 = 1;
            int ok = 1;
            for (int i = 1; i <= n; ++i)
            {
                if (lir[i])
                {
                    if (t1 == t2)
                    {
                        nir[t1] = 1;
                    }
                    else
                    {
                        ok = 0;
                        break;
                    }
                    t1 = t2 = i;
                }

                if ((a[i] >> d) & 1)
                {
                    std::swap(a[i], a[t1++]);
                }
                if (!((b[i] >> d) & 1))
                {
                    std::swap(b[i], b[t2++]);
                }
            }
            if (t1 == t2)
            {
                nir[t1] = 1;
            }
            else
            {
                ok = 0;
            }

            if (ok)
            {
                ans += (1 << d);
                for (int i = 1; i <= n; ++i)
                {
                    if (nir[i]) lir[i] = 1;
                }
            }
        }

        printf("%d\n", ans);
    }

    return 0;
}

标签:std,CF1721D,高位,int,long,100005,分裂,Edu134Div2
From: https://www.cnblogs.com/kyeecccccc/p/16632308.html

相关文章