首页 > 其他分享 >洛谷题单指南-字符串-P5283 [十二省联考 2019] 异或粽子

洛谷题单指南-字符串-P5283 [十二省联考 2019] 异或粽子

时间:2024-10-14 15:11:07浏览次数:9  
标签:val int 洛谷题 ll 个数 异或 th 联考

原题链接:https://www.luogu.com.cn/problem/P5283

题意解读:n个整数,每次从从取l~r的数进行异或得到美味值,一共取k次,并计算这k个美味值之和的最大值。

解题思路:

1、如何O(1)的计算l~r数的异或,得到美味值

可以借助前缀和思想,a[i]为第i个数,s[i]表示a[1]~a[i]每个数的异或值,要计算l~r的异或值,只需要s[r]^s[l-1]即可。

因此,一个美味值就是从s[0]~s[n]中任意挑两个值s[i],s[j],i<j进行异或!

2、如何计算k个美味值之和的最大值

美味值既然是从s[0]~s[n]任意挑两个值进行异或,那么可以将s[]中两个数的异或值最大的前k个计算出来,然后求和即可。

计算两个数异或的最大值是一个经典问题,可以借助Trie树来实现。

但是这里,需要计算的是异或值第k大的数,并且s[i]、s[j]的最大异或值是对称的。

对于异或值对称的问题,可以不必特别处理,只用把k扩大2倍,计算前2k个最大的异或值,然后加起来,结果除以2即可。

关键问题只剩一下一个:如何计算与一个数异或第k大的值?思路如下:

在对每个数建立trie树时,记录每个结点所承载的数的个数,

在查找与一个数x异或第k大的数时,我们根据异或相反更大的原则,如果相反路径上的节点承载的数的个数大于等于k,那么就走相反路径,

如果相反路径上的节点承载的数的个数小于k,那么第k大的数一定在另一条路径上,同时将要查找的第k个数减去相反路径承载的数的个数。

要找到最大的2k个异或值,先求n个数每个数异或第k大值(初始k=1),存入优先队列,每次取队头(异或值最大者),然后计算与队头那个数异或第k+1大值放入优先队列,直到取出2k个数为止。

语言有点绕,看代码会更好理解。

注意数字的取值范围,全程long long。

100分代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 500005;
int n, k;
ll a[N], s[N];
int son[N * 32][2], idx, w[N * 32]; //w存储每个结点所承载的数的个数

struct Node
{
    int x; //第x个数
    int th; //与第x个数异或第th大的值
    ll val; //异或值

    bool operator < (const Node &node) const
    {
        return val < node.val; //val大的在堆顶
    }
};
priority_queue<Node> q;
ll ans;

void add(ll val)
{
    int u = 0;
    for(int i = 31; i >= 0; i--)
    {
        int v = (val >> i) & 1; //从高到低取val的二进制位
        if(!son[u][v]) son[u][v] = ++idx;
        u = son[u][v];
        w[u]++;
    }
}

//查找与val异或第th大的结果
ll find(ll val, int th)
{
    int u = 0;
    ll res = 0;
    for(int i = 31; i >= 0; i--)
    {
        int v = (val >> i) & 1; //从高到低取val的二进制位
        if(w[son[u][!v]] >= th) //如果与当前二进制位相反的路径存在超过th个数就优先走这条路径
        {
            u = son[u][!v];
            res = 2 * res + 1; //相反的二进制异或得1,整体结果上要加上二进制1产生的贡献
        }
        else 
        {
            th = th - w[son[u][!v]];
            u = son[u][v];
            res = 2 * res; //相同二进制异或得0,整体结果上要加上二进制0产生的贡献
        }
    }
    return res;
}

int main()
{
    cin >> n >> k;
    for(int i = 1; i <= n; i++) 
    {
        cin >> a[i];
        s[i] = s[i - 1] ^ a[i];
    }

    for(int i = 0; i <= n; i++) add(s[i]);
    
    k = 2 * k; //由于s中两个数的最大异或值互为一致,所以找到2k个最大的,然后加起来除以2即可
    for(int i = 0; i <= n; i++) //把所有与s[i]异或值第一大的加入优先队列
    {
        ll val = find(s[i], 1);
        q.push({i, 1, val});
    }
    while(k--) //重复2k次,取前2k个最大的异或值
    {
        Node node = q.top();
        ans += node.val;
        q.pop();
        if(node.th < n)
        {
            node.th++;
            node.val = find(s[node.x], node.th);
            q.push(node);
        }   
    }
    
    cout << ans / 2;

    return 0;
}

 

标签:val,int,洛谷题,ll,个数,异或,th,联考
From: https://www.cnblogs.com/jcwy/p/18458680

相关文章

  • 10.11日noip多校联考总结
    10.11日noip多校联考总结T1看到感觉像是一个很玄学的题目,在考场上推了大概一个多小时,又写了大概半个小时,终于调出来了。谨记:三分取mid需要进行浮点数运算。对于每一行和每一列定义两个数组来记录要加多少,因为我们只需要知道其中任意一个数就可以推出所有的数,那么考虑枚举x0,来......
  • 10.10日noip多校联考总结
    10.10日noip多校联考总结T1感觉就是个dij再多记录一个换乘次数然后就像普通dij一样跑就行了。但是必须得将换乘次数放进dis数组中当成一个状态记录下来,不能只记录在堆中,不然做法会假。T2发现m=0的部分分就是用一个数据结构维护区间最大子段和。m=1/2就是同时维护一个最大值......
  • 洛谷 P7517 [省选联考 2021 B 卷] 数对
    题目传送门解题思路其实你只要知道:这题你就秒了。我们发现 ,于是开一个桶来统计每个数出现的数量。我们只需要枚举每一个数的倍数,然后统计。最后,如果一个数出现了多次,再特判一下即可。代码#include<bits/stdc++.h>usingnamespacestd;intn;intcnt[500001];......
  • 洛谷题单指南-字符串-P2580 于是他错误的点名开始了
    原题链接:https://www.luogu.com.cn/problem/P2580题意解读:给n个字符串,再依次处理m个字符串,对于每个字符串,如果在前面n个字符串中输出OK,如果不在n个字符串中输出WRONG,如果在n个字符串中且不止一次查询过输出REPEAT。解题思路:1、set/map方法很简单直接,用set存下前n个字符串,map......
  • 洛谷题单指南-字符串-P1481 魔族密码
    原题链接:https://www.luogu.com.cn/problem/P1481题意解读:在n个字符串中找到最长的词链长度,定义字符串a、b、c可以形成词链,即a是b的前缀、b是c的前缀。解题思路:1、Trie树定义Trie树,也称前缀树、字典树,核心思想是将字符串拆解为单个字符,每个字符是树的一条边,节点是字符添加到树......
  • 洛谷题单指南-字符串-P4391 [BOI2009] Radio Transmission 无线传输
    原题链接:https://www.luogu.com.cn/problem/P4391题意解读:s1由若干个s2组成,求s2的最小长度,注意题目中说明s1是子串,但是不影响,可以认为s1是补全的由若干s2组成的字符串。解题思路:设s1由x个s2组成,如图所示设s1的Next数组从0开始,那么其最长相同前后缀长度为x-1个s2,即Next[s1.siz......
  • [省选联考 2024] 魔法手杖
    一年之后再看好歹是会双log做法的84分的,虽然可能被卡常首先显然有\(x\oplusy\lex+y\)。对于一个最优的方案\(S,x\)你显然如果不影响$\oplus$部分的最值的话移走的最优的。所以我们只会将会影响$\oplus$部分最值的留在\(S\)。考虑二分答案\(mid\),判断有没有\(\ge......
  • 洛谷题单指南-字符串-P3375 【模板】KMP
    原题链接:https://www.luogu.com.cn/problem/P3375题意解读:给定两个字符串:原串s,模式串p,求p在s中出现的所有位置,并输出p的长度为1~p.size()的子串的最长相同真前、后缀的长度。解题思路:KMP模版题,分两问,第一问通过KMP核心算法实现,第二问输出模式串的Next数组内容,接下来一一解读。......
  • 10.8日noip联考总结
    10.8日noip联考总结T1考试的时候没有想到可以快速用组合数进行统计答案,于是在正常的匹配栈里还套了一个\(O(n)\)的统计答案。其实只需要在里面统计个数,在用乘法原理就可以了。括号匹配引导我们使用匹配栈,而需要快速统计答案又可以想到组合计数。T2这题不用输出方案的话就......
  • 10.7 noip多校联考与牛客CSP-S总结
    我在这里对我今天在牛客考试中进入洛谷做出深刻的反省,我不应该在考试的时候上与考试无关的网站(洛谷),保证没有下犯,在该做什么的时候就做什么,分清主次。10.7noip多校联考与牛客CSP-S总结noip联考T1是一道类似于概率计数DP的题,统计概率。通过题目给出的信息,可以发现使用概率,而统......