首页 > 其他分享 >UOJ NOI Round #7 Day1 比特迷宫 个人记录

UOJ NOI Round #7 Day1 比特迷宫 个人记录

时间:2024-11-13 19:42:40浏览次数:1  
标签:opt cnt NOI int void Day1 read popcount UOJ

思路

构造,且上界并不是特别严格。/bx/bx/bx

首先加法比较“混合”,考虑转成位运算,具体地,钦定操作的 \(a, b\) 满足 \(a\&b = 0\)。

考虑递归成子问题,按照 popcount 分组,有一个关键观察是:我们在操作一个 \(a|b = c\) 的时候,可以将任意几个 \(d\&c = d\) 且 \(popcount(d) = popcount(c) - 1\) 的 \(a_d\) 01 翻转。

具体而言,假设我们在操作 10111,我们要使得 10110 和 10101 01翻转,那我们可以使 a|b = 10111,且 b = 00011,即我们要的 \(d\) 的缺的 1。

发现这个时候 < k - 1 的位上的 a 会受到一堆操作的影响,那我们直接先不管它,因为我们在操作 \(popcount = i\) 的时候 \(popcount > i\) 的是不会受影响的所以递归成子问题即可。

那么我们考虑求出 \(T_{1\sim k}\) 使得 \(T_i\) 能覆盖所有 \(popcount = i - 1\)。这个可以贪心求,每次求最大的可行的即可(可以用桶优化),不一定最优但是够了,我构造出来的 \(\sum T_k = 159599\),不知道为啥,其他人好像可以构造出 157884。哦,他们选择的是覆盖最多的情况下最小的值加入 T 中,而我是随便选的,不知道为什么他们会更优/yun

有知道的老哥能不能教教我/kel

好像没什么细节,注意一开始若 \(a_{n - 1}\not= 1\) 的话要额外进行一次操作使得 \(a_{n - 1}\) 变为 1.

代码

const int N = 1 << 20;
const int LogN = 20;
int n, k, _, tot;
int a[N], vis[N], cnt[N], inT[N];
vector <int> pos[LogN + 1], val[LogN + 1], T[LogN + 1];

vector <pii> opt;
void answer(int a, int b) {
    assert((a & b) == 0);
    int s = b;
    do {
        Main::a[a | s] ^= 1;
    } while(s && (s = (s - 1) & b, 1));
    opt.eb(a, b);
}
void output() {
    printf("%llu\n", opt.size());
    for (pii _ : opt) {
        int a = _.fi, b = _.se;
        printf("%d %d\n", a, b);
    }
    fflush(stdout);
}

void skymaths() {
    read(n, k, _);
    for (int i = 0; i < n; ++i) read(a[i]);
    // read(k); n = 1 << k;
    for (int i = 0; i < n; ++i) {
        vis[i] = 1;
        pos[cnt[i] = __builtin_popcount(i)].emplace_back(i);
    }
    rep (c, 1, k) {
        // 求 T(c),即覆盖所有 T(c - 1)
        for (int i = 0; i <= k; ++i) val[i].clear();
        for (int v : pos[c]) {
            val[c].eb(v);
            assert(cnt[v] == c);
            // printf("c = %d, v = %d\n", c, v);
        }
        per (i, k, 1) {
            for (int v : val[i]) {
                if (cnt[v] != i) {
                    // printf("    %d cnt -> %d\n", v, cnt[v]);
                    // assert(cnt[v] < i);
                    val[cnt[v]].eb(v);
                    continue;
                }
                T[c].eb(v); ++tot;
                inT[v] = 1;
                rep (j, 0, k - 1) {
                    if ((v >> j & 1) && vis[v ^ (1 << j)]) {
                        int t = v ^ (1 << j);
                        vis[t] = 0;
                        rep (bit, 0, k - 1) {
                            if (t >> bit & 1) continue;
                            --cnt[t ^ (1 << bit)];
                        }
                    }
                }
            }
        }
    }

	// 此时输出 tot 就是 sum |Tk|

    if (!a[n - 1]) answer(n - 1, 0);

    per (i, k, 1) {
        for (int v : T[i]) {
            int msk = 0;
            rep (j, 0, k - 1) {
                if (v >> j & 1) {
                    if (a[v ^ (1 << j)] != inT[v ^ (1 << j)]) msk |= 1 << j;
                }
            }
            answer(v ^ msk, msk);
        }
    }

    rep (i, 0, n - 1) {
        if (a[i] != 0) {
            cerr << "Wrong on i = " << i << endl;
        }
    }

    output();
	
    // check 正确性用的代码
	
    // clr(vis);
    // rep (c, 1, k) {
    //     for (int v : T[c]) {
    //         rep (j, 0, k - 1) {
    //             if (v >> j & 1) {
    //                 vis[v ^ (1 << j)] = 1;
    //             }
    //         }
    //     }
    // }
    // rep (i, 0, n - 1) {
    //     if (!vis[i]) {
    //         printf("wrong on i = %d\n", i);
    //     }
    // }

    // printf("%d\n", tot);
    // return ;
    // rep (c, 1, k) {
    //     printf("T(%d) = \n", c);
    //     for (int v : T[c]) {
    //         printf("%d ", v);
    //     }
    //     printf("\n");
    // }
}

标签:opt,cnt,NOI,int,void,Day1,read,popcount,UOJ
From: https://www.cnblogs.com/SkyMaths/p/18544624

相关文章

  • [NOI2021] 轻重边
    气死我了这题,还是写一下题解首先有一个非常好的转化,你可以把给定操作转为树上颜色问题假设将操作\(1\)改成“将从\(x\)到\(y\)路径上的所有点都涂上一种新的颜色”,那么可以发现,与路径上的点相邻的所有非路径点,与路径上的点颜色必然不同,路径上的点之间两两必然相同因此就......
  • [题解]P3119 [USACO15JAN] Grass Cownoisseur G
    P3119[USACO15JAN]GrassCownoisseurG显然我们可以先跑强连通分量,由\(x\)个点缩成的新点\(u\)权值为\(v[u]=x\)。下文中的节点\(1\)均表示缩点后节点\(1\)所在的节点。我们在缩点后的DAG上跑拓扑排序,预处理出\(fa[i]\)和\(fb[i]\),分别表示“\(1\)到\(i\)路径的点权和”,“\(i......
  • noip模拟12
    A花鳥風月对于每个区间,若左边端点为\(l\),右边端点为\(r\),那这个地方能放下的线段数则为\(\frac{r-l}{a+1}\)。那么每进来一个坏点,只会影响它的前驱后继的区间。那我们用set或者map维护一下前驱后继,每次加点去抵消它的区间的影响,再加回来就可以了。点击查看代码#incl......
  • NOIP 模拟赛:2024-11-11
    T1:法一:\(O(n^2)\)的DP。\(dp[i][j][0/1]\)表示在\(i\)的子树内染色,\(i\)是红/黑,使得每个要求的结点的黑点个数都等于\(j\)。法二:\(O(n)\)的神秘做法。取出最浅的被要求结点,把深度\(\le\)它的都染成黑色,其余点都染成红色。T2:对于一个元素属于\([0,2^m)\),且互不相......
  • NOIP2024 前集训:NOIP2024加赛 3(欢乐赛)
    前言再次考古,现在才写。这场叫欢乐赛,搬的CF,不知道OJ哪儿来的RMJ。就记得T3一直往数据结构上想浪费好多时间,结果发现是结论题\(O(n)\)可做。T1SakurakoandWater虽然我之前不知道主对角线是什么东西,但是看完题目自动把他过滤成左上角到右下角了(不知道当时怎么想的,好......
  • NOIP2021 数列
    NOIP2021数列算法一最暴力的爆搜,枚举每个位置所有填值的情况,时间复杂度\(O(n^m)\)。可以拿到20分。算法二没那么暴力的爆搜,注意到填数的具体位置不重要,只关系每种数的出现次数。考虑暴力枚举每个数出现了多少次,记数字\(i\)出现了\(x_i\)次。所求即为下面这个不定方程解......
  • [Ynoi2018] 未来日记
    [Ynoi2018]未来日记老早之前就想写了,人生中第一道大分块,调了一上午+下午一个小时,对拍了不知道多少万组,终于过了。\[\Huge{本题不卡常本题不卡常本题不卡常本题不卡常本题不卡常本题不卡常本题不卡常}\]\[\Huge{快来写快来写快来写快来写快来写快来写快来写快来写快来写快来写......
  • [题解]P3225 [HNOI2012] 矿场搭建
    P3225[HNOI2012]矿场搭建挖煤点坍塌相当于把该点和与其相连的边在图上删掉。借用wjyyy的题解,我们定义“叶子连通块”为“只包含\(1\)个割点的点双连通分量”,“非叶子连通块”为“包含\(\ge2\)个割点的点双连通分量”。如下图,橙色点是割点,红色框圈出的是点双,加粗的是叶子连通......
  • P8868 [NOIP2022] 比赛(线段树维护区间历史和)
    题意给定排列\(a,b\),\(q\)次询问\(l,r\),你需要求出\(\sum_{l\lel'\ler'\ler}(\max_{i=l'}^{r'}a_i)(\max_{i=l'}^{r'}b_i)\)对\(2^{64}\)取模的值。\(n,q\le2.5\times10^5\)分析根据经典套路,按\(r\)扫描线,维护两个单调栈,那么加入一个数就相当于进行若干段区......
  • [2024.11.13]NOIP 模拟赛
    T1怎么自然溢出被卡了啊(upd:不是哈希被卡了,是大数据里塞小数据被坑了)T2怎么看不清题目要求啊T3怎么都记得欧拉定理啊T4怎么暴力全机房就我一个写挂了啊……赛时T1题目上说是背包,但是数据范围给到了\(2^{18000}\),所以一眼是结论题。题目上\(a_i\)全部互质的条件很独特,所以我......