首页 > 其他分享 >2024ccpc线性基与校赛线性基

2024ccpc线性基与校赛线性基

时间:2024-09-10 10:46:15浏览次数:9  
标签:基与 leq int ll long 序列 异或 线性 校赛

异或空间线性基

我终于意识到写题解有多重要了

2024 CCPC 网络赛 Problem J. 找最小

Mandy 发现了两个很好玩的长度为\(n\)的序列,记为\(a,b\),她觉得一个序列的无趣度为序列内所有元素的异或和。

现在她想要这两个序列尽可能有趣,具体来说,她希望最无趣的序列尽可能有趣。她觉得交换两个序列中对应位置的元素是无伤大雅的,可以进行任意次这样的操作。

现在她想要知道,最有趣的情况下两个序列无趣度较大者的无趣度是多少呢?

形式化地来说,你有两个长度为 \(n\) 的序列 \(a,b\) ,你可以进行若干次选择一个 \(i\left(1\leq i\leq n\right)\) ,然后交换 \(a_i,b_i\) ,希望使得 \(\max\{f(a),f(b)\}\) 最小,其中对于一个序列 \(A,f(A)=\oplus_i=1^nA_i\) (\(\oplus\)表示按位异或) 。

Output

第一行一个整数 \(T\left ( 1\leq T\leq 10^5\right )\), 表示数据组数。

对于每组数据,第一行一个整数 \(n\) \((1≤n≤10^6)\) 。

第二行 \(n\) 个整数 \(a_1,a_2,\cdots,a_n\) \((0\leq a_i<2^{31})\)。

第三行\(n\)个整数\(b_1,b_2,\cdots,b_n\) \((0\leq b_i<2^{31})\) 。

保证对于所有数据,\(\sum n\leq10^6\)。

Solution

首先有一个重要观察,如果当前两个数组的异或和分别是 \(A\) 和 \(B\), 使得 \(a_i\) 与 \(b_i\) 交换的操作即为

$A\oplus a_i \oplus b_i $ 与 $B\oplus a_i \oplus b_i $

即 \(c_i = a_i \oplus b_i\) , 在数组 \(c\) 中选择若干个数字异或

于是可以考虑线性基,设异或出的数字为 \(X\)

问题进展到这里,我们对 \(X\) 希望是什么样子的已经可以贪心得到了,从高位到低位贪心。

而线性基刚好异或上这一个,那么这个对应的这一位就在结果中出现,不异或这一个,就不会出现。

接下来就是分类讨论了,当前位若 \(A_i = B_i\) ,则去看线性基有没有这一位再直接选择异或或者不异或,我们可以强制 \(A > B\),不然交换位置。那么第一个出现不同的情况的时候,肯定是 \(A_i = 1 \; \; B_i = 0\) 的情况,这时候我们如果选择异或这一位的话,那么 \(B\) 求出的答案就肯定大于 \(A\) 求出的答案了,所以,之后所有的选择都得偏袒 \(B\)。 相当于(在大的情况下我偏袒了 \(A\),那么在每一个小的情况,我都需要去补偿 \(B\),相反也是一样的)

下面是参考代码

点击查看代码
// Created by qyy on 2024/9/9.

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

#define PII pair<int, int>
#define endl "\n"

const long long inf = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;

int n;
ll a[N], b[N];

bool zero;
ll p[N];
int xxjcnt;
int Gauss(){
    // 此构造线形基出的是降序排序,大小为 xxjcnt 个,编号从 1 开始
    for(int i = 1; i <= n; i++){
        p[i] = a[i];
    }
    int i, k = 1;
    ll j = (ll) 1 << 62;  // 注意不是 63;
    for(; j; j >>= 1){
        for(i = k; i <= n; i++) {
            if (p[i] & j) {
                break; // 找到了第 j 位上的 1
            }
        }
        if(i > n){
            continue; // 没有找到第 j 位上的 1
        }
        swap(p[i], p[k]);
        for(i = 1; i <= n; i++){
            if(i != k && p[i] & j){
                p[i] ^= p[k];
            }
        }
        k++;
    }
    k--;
    if(k != n){
        zero = true;
    }else{
        zero = false;
    }
    return k;
}

ll toj[100]; // 需要更新;
int cal(ll x){
    for(int i = 62; i >= 0; i--){
        if((1LL << i) & x){
            return i;
        }
    }
}

void solve() {
    cin >> n;
    for(int i = 0; i < 90; i++){
        toj[i] = 0;
    }
    ll A = 0, B = 0;
    for(int i = 1; i <= n; i++){
        cin >> a[i];
        A ^= a[i];
    }
    for(int i = 1; i <= n; i++){
        cin >> b[i];
        B ^= b[i];
    }
    for(int i = 1; i <= n; i++){
        a[i] ^= b[i];
    }
    if(A < B){
        swap(A, B);
    }

    xxjcnt = Gauss();
    for(int i = 1; i <= xxjcnt; i++){
        int x = cal(p[i]);
        toj[x] = p[i];
    }
    ll ans1 = 0, ans2 = 0;
    bool flag = false;
    for(int i = 62; i >= 0; i--){
        ll x = (1LL << i);
        if((x&A) && (!(x&B))){
            // 开始分类;
            if(toj[i] != 0){
                if(flag){
                    ans2 ^= toj[i]; // 应该按照 B 小的走,因为现在 B 异或出来一定比 A 大
                }else{
                    ans1 ^= toj[i]; // 应该按照 B 小的走,因为现在 B 异或出来一定比 A 大
                }
            }
            flag = true;
        }else if((x&A) && (x&B)){
            // 需要 toj[i] 参与进来
            if(toj[i] != 0){
                ans1 ^= toj[i];
                ans2 ^= toj[i];
            }
        }else if((!(A&x)) && (!(B&x))){
            // 不需要任何参与
        }else{
            // 给两个答案都计算上
            if(toj[i] != 0){
                ans1 ^= toj[i];
            }
        }
    }
    ll res1 = max(A^ans1, B^ans1);
    ll res2 = max(A^ans2, B^ans2);
    cout << min(res1, res2) << endl;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

2024 校赛(团队赛)

作为 xxcdsg 的舔狗,Taibo 经常邀请 xxcdsg 一起玩无聊的游戏。

有一个长度为 \(n\) 的序列 $[a_1,a_2,...,a_n] $ , Taibo 和 xxcdsg 轮流在这个序列中取一个非空子序列并删除该子序列直到序列为空,Taibo 是先手。 游戏结束后,定义游戏的得分为 Taibo 和 xxcdsg 每次所取的子序列的异或和的总和。

现在,Taibo 想要最大化这个得分,而 xxcdsg 则想要最小化该得分。如果双方都采取最佳策略的情况下,最终的得分将是多少?关于非空子序列的定义:如果正整数 \(i_1,i_2,...,i_k(k\geq1)\) 满足\(1\leq i_1<i_2<...<i_k\leq n\), 那么 \([a _{i_1},a_{i_2},...,a_{i_k}]\)是 \([a_1,a_2,...,a_n]\) 的一个非空子序列。

例如,[1,2,6],[1,3,5],[4],[1,3,5,2,4,6]是[1,3,5,2,4,6]的非空子序列,而[1,2,3],[4,5],[1,2,3,4,5,6]不是。

\(n\leq2\times10^5,0\leq a_i<2^{20}\)

solution

首先一个重要观察,不管 Taibo 第一轮选了什么,剩下的所有数 xxcdsg 一定会全部全部拿光。原因即异或是不进位加法,\(a \oplus b \leq a + b\) ,于是问题简化为在一个数组中选择若干个数异或,加上剩余的数异或,求最大结果。

观察到数据范围,线性基后,可以搜索出每一种可能,于是枚举取最大值就行了。

参考代码如下:


<details>
<summary>点击查看代码</summary>

// Created by qyy on 2024/9/9.

include <bits/stdc++.h>

using namespace std;

typedef long long ll;

define PII pair<int, int>

define endl "\n"

const long long inf = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 10;
const int mod = 7;

int n;
ll a[N];

bool zero;
ll p[N];
int xxjcnt;
int Gauss(){
// 此构造线形基出的是降序排序,大小为 xxjcnt 个,编号从 1 开始
for(int i = 1; i <= n; i++){
p[i] = a[i];
}
int i, k = 1;
ll j = (ll) 1 << 62; // 注意不是 63;
for(; j; j >>= 1){
for(i = k; i <= n; i++) {
if (p[i] & j) {
break; // 找到了第 j 位上的 1
}
}
if(i > n){
continue; // 没有找到第 j 位上的 1
}
swap(p[i], p[k]);
for(i = 1; i <= n; i++){
if(i != k && p[i] & j){
p[i] ^= p[k];
}
}
k++;
}
k--;
if(k != n){
zero = true;
}else{
zero = false;
}
return k;
}

ll ans = 0, sum = 0;
void dfs(int pos, ll cur){
if(pos == xxjcnt + 1){
ans = max(ans, cur + (sum^cur));
return ;
}
dfs(pos + 1, cur);
cur ^= p[pos];
dfs(pos + 1, cur);
}
void solve() {
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i];
sum ^= a[i];
}
xxjcnt = Gauss();
ans = sum;
dfs(1, 0);
cout << ans << endl;
}

signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
//cin >> t;
while (t--) {
solve();
}
return 0;
}

</details>

标签:基与,leq,int,ll,long,序列,异或,线性,校赛
From: https://www.cnblogs.com/9102qyy/p/18405987

相关文章

  • 线性表的链式存储
    线性表的链式存储1链式存储在一个数据结构中,如果一个结点有多个前驱或后继时,使用顺序存储就比较麻烦,即使是线性结构,如果没有足够大的存储空间供使用,也是无法实现的。这时就可以使用链式下存储,在这种存储方式下,除了存放一个结点的信息外,还需附设指针,用指针来体现结点之间的逻辑......
  • AP510X 单路低压差线性恒流芯片 LED手电筒台灯车灯照明方案
    产品描述AP510X是一系列电路简洁的单路线性LED恒流芯片,适用于3-60V电压范围的LED恒流调光领域。AP510X采用我司算法,可以实现高精度的恒流效果,输出电流恒流精度≤±3%,电源供电工作范围为3-40V,可以轻松满足锂电池以及市场上面中低压的应用需求。PWM调光支持高辉应用,可以支持20K以......
  • 数据结构与算法(三)线性表的定义与抽象数据类型
    目录一、感受线性表的存在二、线性表的定义三、考题模拟1、请问公司的组织架构是否属于线性关系?2、那么班级同学的友谊呢?3、那么班级的点名册是不是线性表?四、抽象数据类型1、数据类型的定义:2、抽象数据类型一、感受线性表的存在    从这一篇开始,我们将介......
  • MATLAB卡尔曼|卡尔曼滤波的公式【线性】
    卡尔曼滤波卡尔曼滤波(KalmanFilter)是一种用于估计系统状态的数学算法,不是类似于高通、低通滤波器那样的频域滤波。卡尔曼滤波基于线性动态系统的假设,它将系统的状态表示为均值和协方差矩阵,通过递归地更新和预测这些值来实现对系统状态的估计。卡尔曼滤波有两个主要的步......
  • 线性代数 第五讲:线性方程组_齐次线性方程组_非齐次线性方程组_公共解同解方程组_详解
    线性方程组文章目录线性方程组1.齐次线性方程组的求解1.1核心要义1.2基础解系与线性无关的解向量的个数1.3计算使用举例2.非齐次线性方程的求解2.1非齐次线性方程解的判定2.2非齐次线性方程解的结构2.3计算使用举例3.公共解与同解3.1两个方程组的公共解3.2同......
  • 《动手学深度学习》笔记4——线性回归 + 基础优化算法
    李沐老师:线性回归是机器学习最基础的一个模型,也是我们理解之后所有深度学习模型的基础,所以我们从线性回归开始1.线性回归由于是案例引入,没有很难的知识点,咱直接贴上李沐老师的PPT:1.1线性模型--单层神经网络李沐老师:神经网络起源于神经科学,但现在深度学习的发展......
  • 线性因子模型 - 概率PCA和因子分析篇
    序言在探索数据科学与机器学习的浩瀚领域中,深度学习作为一股不可小觑的力量,正以前所未有的方式重塑着我们对数据处理与知识发现的理解。在这一宏大的框架下,概率主成分分析(Probabilistic PCA, pPCA......
  • 20240911_220441 公共基础 线性链表
    什么是线性链表单向线性链表双向线性链表带链的栈带链队列线性链表的运算循环链表考点小结习题c习题a习题b习题c......
  • 数据结构基础讲解(三)——线性表之循环链表专项练习
    本文数据结构讲解参考书目:通过网盘分享的文件:数据结构 C语言版.pdf链接: https://pan.baidu.com/s/159y_QTbXqpMhNCNP_Fls9g?pwd=ze8e 提取码:ze8e数据结构基础讲解(二)——线性表之单链表专项练习-CSDN博客 个人主页:樱娆π-CSDN博客目录循环链表双向链表......
  • 秋招校招,在线性格测评应该如何应对
    秋招校招,如果遇到在线测评,如何应对?这里写个总结稿,希望对大家有些帮助。在线测评是企业深入了解求职人的渠道,如果是性格测试,会要求测试者能够快速答出,以便于反应实际情况(时间限制)。性格测试主要是为了找出岗位和性格的匹配关系,这方面比较知名和成熟的测评也挺多的,比如MBTI职业......