I love max and multiply(sosdp高位前缀和求超集)

I love max and multiply

problem6971

题意

Mr.I has two sequence Ai and Bi of length n,(0≤i≤n−1).
Define an array C of length n, where Ck=max{AiBj}, satisfying (i&j≥k).
& is the button under binary Bitwise AND operation.
Please calculate the value of ∑n−1i=0Ci, modulo 998244353.

题解

sosdp求高维前缀和,然后求超集,每一种情况都由上一种情况可以推出
即7\((111)_2\)可以推出1\((001)_2\),2\((001)_2\),3\((010)_2\),4\((100)_2\),5\((101)_2\),6\((110)_2\),而其中4\((100)_2\),2\((010)_2\),1\((001)_2\)不能直接推出,但可以通过6\((110)_2\),5\((101)_2\),3\((011)_2\)间接推出

AC代码

#include<bits/stdc++.h>
#define int long long
#define ll int
using namespace std;

const int mod=998244353;
const int inf=1ll<<62;

int getmax(int a,int b,int c,int d){
    //最大*最大,最小*最小,最大*最小 求的就是最大了
    int ans1=d*b,ans2=a*c,ans3=a*d,ans4=b*c;
    return max(ans1,max(ans2,max(ans3,ans4)));
}

void slove(){
    int n;
    scanf("%lld",&n);
    vector<int>a(n+10),b(n+10);
    vector<int>minl(n*5,inf),maxl(n*5,-inf),minr(n*5,inf),maxr(n*5,-inf);
    for(int i=0;i<n;i++)scanf("%lld",&a[i]),minl[i]=maxl[i]=a[i];
    for(int i=0;i<n;i++)scanf("%lld",&b[i]),minr[i]=maxr[i]=b[i];
    int cnt=0;
    while(n>>cnt)cnt++;
    cnt++;//求有几位二进制
    //求超集
    for(int i=n-1;i>=0;i--){//从后往前遍历,后可以影响前面的数据
        for(int j=0;j<=cnt;j++){//遍历每一位
            if((i>>j&1)){
                //i^(1<<j)<=>i-(1<<j)
                maxl[i^(1<<j)]=max(maxl[i],maxl[i^(1<<j)]);
                minl[i^(1<<j)]=min(minl[i],minl[i^(1<<j)]);
                maxr[i^(1<<j)]=max(maxr[i],maxr[i^(1<<j)]);
                minr[i^(1<<j)]=min(minr[i],minr[i^(1<<j)]);
            }
        }
    }
    vector<int>ans(n+10);
    ans[n]=-inf;
    int res=0;
    for(int i=n-1;i>=0;i--) {
        ans[i] = max(ans[i + 1], getmax(minl[i], maxl[i], minr[i], maxr[i]));
        res = ((res + ans[i]) % mod + mod) % mod;
    }
    printf("%lld\n",res);
    return;
}


signed main(){
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    int t;
    scanf("%lld",&t);
    while(t--)slove();
    fclose(stdin);
    fclose(stdout);
    return 0;
}

//1
//4
//9 1 4 4
//5 4 1 9
posted @ 2021-07-23 10:01  塔塔开  阅读(138)  评论(0)    收藏  举报