6971 I love max and multiply 位运算小性质

博客内容涉及位运算在数组处理中的应用,通过位运算性质优化求解两个数组元素的最大乘积问题,使用二进制枚举和动态规划方法。代码实现包括数组初始化、动态更新和结果计算,最后输出模意义下的最大乘积。

题意:两个数组a,b,数组ci = max(ai*bj)(同时i&j >= k),求数组c

位运算小性质:当i&j==0时,i xor j >= i, i xor j >= j。
思路:令sum = 2^k >= n, i 从 sum到1枚举,j从2的0次方开始枚举,2的一次方,2的二次方一直到2的k次方,太巧妙了,举个例子,一个二进制数10011000,j == 1的时候会继承10011000,j == 10的时候,他会继承10011010,这时候的10011010已经继承了10011011,所以这样遍历是可以把所有i xor j >= i 的情况全部遍历到的,看不明白一定要在草稿纸上写一下,我当天补的题过了一个星期回头看都有点懵。。

#include<bits/stdc++.h>
#define LL long long
#define INF INT64_MAX
#define MOD 998244353
#define stree SegTree[root]
#define lson SegTree[root << 1]
#define rson SegTree[root << 1 | 1]
using namespace std;
const int N = 1000005;
LL a[N], b[N], A[N], B[N], ans[N];
int main()
{
    int t, n;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d", &n);
        for(int i = 0;i < n;i++) scanf("%lld", &a[i]), A[i]=a[i];
        for(int i = 0;i < n;i++) scanf("%lld", &b[i]), B[i]=b[i];
        LL sum=1;
        while(sum<n) sum<<=1;
        for(int i = n;i < sum;i++) A[i]=B[i]=-INF, a[i]=b[i]=INF;
        for(int j = 1;j < sum;j<<=1)
        {
            for(int i = sum-1;i >= 0;i--)
            {
                //printf("%d %d\n", i, j);
                if(! (i&j))
                {
                    A[i]=max(A[i], A[i^j]);
                    B[i]=max(B[i], B[i^j]);
                    a[i]=min(a[i], a[i^j]);
                    b[i]=min(b[i], b[i^j]);
                    //printf("%lld %lld %lld %lld\n", A[i],B[i], a[i], b[i]);
                }
            }
        }
        ans[n]=-INF;
        for(int i = n-1;i >= 0;i--)
        {
            ans[i] = -INF;
            if(A[i]!=-INF && B[i]!=-INF) ans[i] = max(ans[i], A[i]*B[i]);
            if(A[i]!=-INF && b[i]!=INF) ans[i] = max(ans[i], A[i]*b[i]);
            if(a[i]!=INF && B[i]!=-INF) ans[i] = max(ans[i], a[i]*B[i]);
            if(a[i]!=INF && b[i]!=INF) ans[i] = max(ans[i], a[i]*b[i]);
            //printf("%lld %lld %lld %lld\n", A[i],B[i], a[i], b[i]);
            //printf("ans = %lld\n", ans[i]);
            ans[i]=max(ans[i], ans[i+1]);
        }
        LL res = 0;
        for(int i = n-1;i >= 0;i--)
        {
            ans[i]%=MOD;
            res = (res+ans[i])%MOD;
        }
        printf("%lld\n", (res+MOD)%MOD);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值