2021“MINIEYE杯”中国大学生算法设计超级联赛(2)1011.I love max and multiply (思维,位运算)

2021/7/30 17:35:58

本文主要是介绍2021“MINIEYE杯”中国大学生算法设计超级联赛(2)1011.I love max and multiply (思维,位运算),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

  • 题意:有两个长度为\(n\)的序列\(a\)和\(b\),定义\(C_k=max(A_i,B_j)\ (i\ and\ j\ge k)\),求\(\sum^{n-1}_{i=0}C_i\).

  • 题解:暴力思路:求出所有的\(C_k\),然后从\(n-1\)倒着维护最大值贡献给答案即可.

    根据到这维护最大值这个思想,我们考虑\(i\)&\(j\)=\(i\)的情况,根据&运算的性质,两个数&之后只会不变或者变小,我们倒着枚举\(i\),根据上述性质,我们找\([i,n-1]\)中满足条件的\(j\),这里我们只要看单独的某一个\(1\)即可,可以用dp转移过来,那么我们每次可以得到\([i,n-1]\)中的满足条件的\(j\),更新最大值最小值.最后在求答案贡献的时候,\(A[i]\)表示的是\([i,n-1]\)中的\(i\)&\(j\)=\(i\)的某个位置\(x_1\)的值,同理,\(B[i]\)表示的是某个位置\(x_2\)的值,因为我们在更新的时候保证\(i\)&\(j\)=\(i\),且根据性质\(j\)一定不小于\(i\),那么\(x_1\)&\(x_2\ge i\),然后就根据我们前面的暴力思路求贡献给答案就好了.

  • 代码:

    #include <iostream>
    #include <iomanip>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <queue>
    #include <vector>
    #include <map>
    #include <set>
    #include <unordered_set>
    #include <unordered_map>
    #define ll long long
    #define db double
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 998244353;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
    int lcm(int a,int b){return a/gcd(a,b)*b;}
    
    ll a[N],A[N],b[N],B[N];
    
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
        #ifdef lr001
            freopen("/Users/somnus/Desktop/data/in.txt","r",stdin);
        #endif
        #ifdef lr002
            freopen("/Users/somnus/Desktop/data/out.txt","w",stdout);
        #endif
        int _;
        cin>>_;
        while(_--){
            int n;
            cin>>n;
            rep(i,0,n-1) cin>>a[i],A[i]=a[i];
            rep(i,0,n-1) cin>>b[i],B[i]=b[i];
            int base=0;
            while((1<<base)<=n) base++;  //要包括n
            /* brute_force
            rep(i,0,n-1){
                rep(j,0,n-1){
                    res[i&j]=max(res[i&j],a[i]*b[j]);
                }
            }
            int ans=0;
            per(i,n-1,0){
                res[i]=max(res[i],res[i+1]);
                ans+=res[i];
            }
            cout<<ans<<'\n';
            */
            rep(i,n,(1<<base)-1){
                A[i]=B[i]=-INF;
                a[i]=b[i]=INF;
            }
            per(i,n,0){
                rep(j,0,base-1){
                    int cur=1<<j;
                    if((i&cur)==0){
                        A[i]=max(A[i],A[i^cur]);
                        B[i]=max(B[i],B[i^cur]);
                        a[i]=min(a[i],a[i^cur]);
                        b[i]=min(b[i],b[i^cur]);
                    }
                }
            }
            ll mx=-1e18;
            ll ans=0;
            per(i,n-1,0){
                ll res=-1e18;
                res=max(res,A[i]*B[i]);
                res=max(res,A[i]*b[i]);
                res=max(res,a[i]*B[i]);
                res=max(res,a[i]*b[i]);
                res=max(res,mx);
                mx=res;
                ans=(ans+res+mod)%mod;
            }
            cout<<ans<<'\n';
        }
    
    
    
        return 0;
    }
    
    


这篇关于2021“MINIEYE杯”中国大学生算法设计超级联赛(2)1011.I love max and multiply (思维,位运算)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程