hihocoder 1496:寻找最大值(高维前缀最大次大值)

【题目链接】 https://hihocoder.com/problemset/problem/1496

【题目大意】

  给定N个数A1, A2, A3, ... AN,
  从中找到两个数Ai和Aj(i≠j)使得乘积Ai*Aj*(Ai&Aj)最大

【题解】

  我们可以枚举x&y的结果z,找出两个数x&y==z使得x*y最大,更新答案即可,
  条件可以被削弱为z为x&y的子集,这种条件放缩不会导致最优解的丢失,
  z为x&y的子集等价于z为x的子集并且z为y的子集。
  那么我们只要找出以z为子集的最大值和次大值,然后枚举z即可计算出答案。
  复杂度O(k*2^k).

【代码】

#include <cstdio>
#include <algorithm>
using namespace std;
struct data{
    int val[2];
    data operator +(const data &rhs)const{
        int t_val[2]={val[0],val[1]};
        for(int i=0;i<2;i++){
            if(rhs.val[i]>t_val[0]){
                t_val[1]=t_val[0];
                t_val[0]=rhs.val[i];
            }else if(rhs.val[i]>t_val[1])t_val[1]=rhs.val[i];
        }return data{t_val[0],t_val[1]};
    }
}dp[(1<<20)+10];
int T,n;
int main(){
    scanf("%d",&T);
    int all=1<<20;
    while(T--){
        for(int i=0;i<all;i++)dp[i]=data{0,0};
        scanf("%d",&n);
        for(int i=1,x;i<=n;i++){
            scanf("%d",&x);
            dp[x]=dp[x]+data{x,0};
        }
        for(int i=0;i<20;i++)
            for(int j=0;j<all;j++)
                if(~j&(1<<i))dp[j]=dp[j]+dp[j|(1<<i)];
        long long ans=0;
        for(int i=0;i<all;i++)ans=max(ans,1LL*i*dp[i].val[0]*dp[i].val[1]);
        printf("%lld\n",ans);
    }return 0;
}
时间: 2024-10-27 19:30:19

hihocoder 1496:寻找最大值(高维前缀最大次大值)的相关文章

hihocoder 1496 寻找最大值

题解: 注意到$ai$只有$1e6$这件事情肯定要枚举和这个有关的东西 考虑枚举$ai&aj$的值就可以了 那么这个集合一定是ai,aj的子集 于是我们对每个集合从大到小枚举丢掉一位转移就行了 这实际上放缩了条件但显然最大值不变 这题并不用用到高维前缀和..但第一次听说于是学习了一下 原文地址:https://www.cnblogs.com/yinwuxiao/p/10107437.html

4.7-4.9补题+水题+高维前缀和

题目链接:51nod 1718 Cos的多项式  [数学] 题解: 2cosx=2cosx 2cos2x=(2cosx)^2-2 2cos3x=(2cosx)^3-3*(2cosx) 数归证明2cos(nx)能表示成关于2cosx的多项式,设为f(n) f(1)=x,f(2)=x^2-2(其中的x就是2cosx) 假设n=1~k时均成立(k>=3) 当n=k+1时 由cos((k+1)x)=cos(kx)cos(x)-sin(kx)sin(x) cos((k-1)x)=cos(kx)cos(x)

同时寻找最大值和第二大值 锦标赛算法

问题:在一个数组中同时寻找最大值和第二大值,这里假设数组的元素个数n大于2 方法一:遍历数组,设置max和secondMax标志,如果有大于max的就更新max,如果有小于max但是大于secondMax的就更新secondMax. 比较次数:在a[0]和a[1]中找出临时的max和secondMax需要一次比较.在剩下的n-2个数中最坏时需要同max和secondMax分别比较,总共比较2(n-2),所以总的比较次数为1+2(n-2).代码如下: void traverse_find(int

hihocoder1496(高维前缀和)

题意:给定N个数A1, A2, A3, ... AN,小Ho想从中找到两个数Ai和Aj(i ≠ j)使得乘积Ai × Aj × (Ai AND Aj)最大.其中AND是按位与操作. 第一行一个整数N(1<=N<=100,000) 第二行N个整数A1, A2, A3, ... AN (0 <= Ai <2^20) 分析: 尝试枚举and值z,那么问题就变成了找寻最大的x*y,使得x&y==z 把这个要求放宽一点,我们来寻找z是x&y子集的情况(这样肯定不会丢掉整体最优

Codeforces 449D:Jzzhu and Numbers(高维前缀和)

[题目链接] http://codeforces.com/problemset/problem/449/D [题目大意] 给出一些数字,问其选出一些数字作or为0的方案数有多少 [题解] 题目等价于给出一些集合,问其交集为空集的方案数, 我们先求交集为S的方案数,记为dp[S],发现处理起来还是比较麻烦, 我们放缩一下条件,求出交集包含S的方案数,记为dp[S], 我们发现dp[S],是以其为子集的方案的高维前缀和, 我们逆序求高维前缀和即可,之后考虑容斥,求出交集为0的情况, 我们发现这个容斥

SPOJ Time Limit Exceeded(高维前缀和)

[题目链接] http://www.spoj.com/problems/TLE/en/ [题目大意] 给出n个数字c,求非负整数序列a,满足a<2^m 并且有a[i]&a[i+1]=0,对于每个a[i],要保证a[i]不是c[i]的倍数, 求这样的a[i]序列的个数 [题解] 我们用dp[i]表示以i为结尾的方案数, 我们发现要满足a[i]&a[i+1]=0,则dp[i]是从上一次结果中所有满足i&j=0的地方转移过来的 i&j=0即i&(~j)=i,即i为~

编程之美3:寻找数组中的最大值和最小值以及最大值和次大值

很开心,这是今天的第三篇文章啦!下午健身也感觉非常过瘾,托付宿舍妹子从日本代购的护肤品也到了.耳边漂浮着Hebe田馥甄的<魔鬼中的天使>文艺的声线,一切都好棒,O(∩_∩)O哈哈~.爱生活,爱音乐,爱运动,额,当然还有要爱学习啦!加油(^ω^) 额,扯远了.第三篇是关于寻找数组中的最大值和最小值.第一次看到这个题目的时候,楼主稍微鄙视了一下,因为觉得这个题目有什么好做的.但是楼主还是看了看<编程之美>上的写的,发现还是有必要记录一下,不一样的思考方式.很赞!大家和楼主一起哦,Are

codeforces 938F(dp+高维前缀和)

题意: 给一个长度为n的字符串,定义$k=\floor{log_2 n}$ 一共k轮操作,第i次操作要删除当前字符串恰好长度为$2^{i-1}$的子串 问最后剩余的字符串字典序最小是多少? 分析: 首先很容易得到一个性质,那就是删除的那些串是可以不交叉的 很容易想到一个很简单的dp dp[i][j]表示考虑原串的前i位,删除状态为j的情况下字典序最小的字符串(注意dp里面保存的是个字符串) 那么很明显就是个O(n^3logn)的dp,无法通过 dp里是一个字符串这个东西是很浪费时间而且很不优美的

[2018.6.21集训]走路-分块高维前缀和-Pollard-Rho

题目大意 给一棵树,每个节点有一个权值$val$. 如果两个点$a$和$b$满足$a$为$b$的祖先且$val[b]$为$val[a]$的约数,那么可以从$a$一步跳到$b$. 求从$1$号节点走到各每个节点的路径数. $n \leq 10^5 , val[i] \leq 10^{18},$保证对于任意节点$i$,$val[i]$为$val[1]$的约数. 题解 首先有定理:一个数$n$的约数个数大概是$n^{\frac{1}{3}}$的级别 然后得到有理有据的一个部分分($val[i] \le