I love max and multiply 题解(二进制dp)

题目链接

题目思路

这个不知道叫啥感觉算是个二进制dp把

\(n\)为化简为\(2\)进制的最高位数

我最开始是直接\(3^n\)枚举子集,但是喜提\(TLE\)

标准是\(n\times2^n\)

每次枚举只枚举比他多一个1的元素,然后从大到小for过去就能得到答案

因为比他多一个1的元素也枚举了比他多一个1的元素,递归的思路,这样其实相当于枚举了他的所有父亲

注意有负数

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
//typedef pair<int,int> pii;
#define fi first
#define se second
#define debug printf("aaaaaaaaaaa\n");
const int maxn=6e5+5,inf=0x3f3f3f3f,mod=998244353;
const ll INF=0x3f3f3f3f3f3f3f3f;
int n;
ll dp1[maxn][2],dp2[maxn][2];
ll ans[maxn];
int main(){
    int _; scanf("%d",&_);
    while(_--){
        scanf("%d",&n);
        for(int i=0,a;i<=n-1;i++){
            scanf("%d",&a);
            dp1[i][0]=dp1[i][1]=a;
        }
        for(int i=0,b;i<=n-1;i++){
            scanf("%d",&b);
            dp2[i][0]=dp2[i][1]=b;
        }
        int m=1;
        while(m<n-1) m=(m<<1);
        for(int i=0;i<=19;i++){
            for(int j=m-1;j>=0;j--){
                if((!(j&(1<<i)))&&j<=n-1&&(j^(1<<i))<=n-1){
                    dp1[j][0]=min(dp1[j^(1<<i)][0],dp1[j][0]);
                    dp1[j][1]=max(dp1[j^(1<<i)][1],dp1[j][1]);
                    dp2[j][0]=min(dp2[j^(1<<i)][0],dp2[j][0]);
                    dp2[j][1]=max(dp2[j^(1<<i)][1],dp2[j][1]);
                }
            }
        }
        ans[n]=-INF;
        ll pr=0;
        for(int i=n-1;i>=0;i--){
            ans[i]=max(max(dp1[i][0]*dp2[i][0],dp1[i][0]*dp2[i][1]),max(dp1[i][1]*dp2[i][0],dp1[i][1]*dp2[i][1]));
            ans[i]=max(ans[i],ans[i+1]);
            pr=(pr+ans[i])%mod;
        }
        printf("%lld\n",(pr%mod+mod)%mod);
    }
    return 0;
}

I love max and multiply 题解(二进制dp)

上一篇:负数补码的求法来由


下一篇:小型mvvm实现原理