• 【17.12.22.B】


    B

    题面描述:

     

    给一个长度为n的序列,a[1], a[2], ... , a[n], 选出连续的k个数,使得这k个数的最大值加这k个数的or值最大。

    假设选出的数为a[l], a[l + 1], ... , a[l + k -1],即求

    max(a[l], a[l + 1], ... , a[l + k -1]) + (a[l] | a[l + 1] | ... | a[l + k -1])

    对于所有的1 <= k <= n,输出答案

     

    输入:

    第一行输入一个n,第二行输入n个数,a[1], a[2], ... , a[n].

    输出:

    输出n行,每行一个整数。第i行表示k = i时的答案。

     

    样例输入:

    3

    1 0 2

    样例输出:

    4

    4

    5

     

    对于20%的数据,1 <= n <= 300

    对于40%的数据,1 <= n <= 5000

    对于100%的数据,1 <= n <= 200000, 0 <= a[i] < 2^16

    【题解】

               ①注意到2^16了吗,有趣的地方就在这里了。

            ②结合|和+的定义我们可以知道,定义f[i]表示长度长度为i的序列的值最大,那么f[i]≥f[i-1];

            ③考虑求f[i],如果一个区间对我们的答案有贡献,那么区间的左右一定是最大值或能使异或值改变的值,而两边都是最大值的话去掉一个也无所谓,所以两边必定有一个能改变异或值的。

            ④可以做到了,枚举左右端点,然后维护其能改变其异或值的位置,最多16个,转移即可!

            (建议看代码)

     1 /*3
     2 1 0 2
     3 好想用linux啊~
     4 其实代码很简单,但是思路很~~怎么说呢
     5 精巧吧;
     6 注意到|和+的单调 ,还有2^16这个数,很容易想到按位搞事情
     7 其实自己是想到前半部分的,但是经验不够,不知道怎么运用,积累重要。 
     8 */
     9 #include <cstdio>
    10 #include <iostream>
    11 #include <cstring>
    12 #include <algorithm>
    13 #include <queue>
    14 #include <vector>
    15 #include <ctime>
    16 #include <cmath>
    17 #define inf 0x3f3f3f3f
    18 #define ll long long
    19 #define N 200010
    20 #define mem(f,a) memset(f,a,sizeof(f))
    21 #define Run(i,l,r) for(int i=l;i<=r;i++)
    22 #define Don(i,l,r) for(int i=l;i>=r;i--)
    23 #define Eun(i,u,E) for(int i=head[u],v=E[i].v;i!=-1;i=E[i].next,v=E[i].v)
    24 using namespace std;
    25 int n,a[N],pre[N],num[N],s[N],top,ans[N];
    26 void solve()
    27 {    mem(pre,0); mem(num,0); top=0;
    28     Run(i,1,n){
    29         while (top&&a[s[top-1]]<=a[i]) top--;
    30         s[top++]=i; 
    31         Run(j,0,15){
    32             if (a[i]&(1<<j)) {
    33                 pre[j]=i;
    34                 num[i]=a[i];
    35             }
    36             else num[pre[j]]|=a[i];
    37         }
    38         Run(j,0,15)if (pre[j]){ 
    39             int l=0,r=top-1;
    40             while (l<r){
    41                 int mid=(l+r)/2;
    42                 if (s[mid]>=pre[j]) r=mid;
    43                 else l=mid+1;
    44             }
    45         int maxn=a[s[l]];
    46         ans[i-pre[j]+1]=max(ans[i-pre[j]+1],maxn+num[pre[j]]);
    47         } 
    48     }
    49 }
    50 int main()
    51 {    freopen("B.in","r",stdin);    
    52     freopen("B.out","w",stdout);
    53     scanf("%d",&n);
    54     Run(i,1,n){
    55         scanf("%d",&a[i]);
    56     } 
    57     solve();
    58     Run(i,1,n/2) a[i]=a[n-i+1];
    59     solve();
    60     Run(i,1,n){
    61         ans[i]=max(ans[i-1],ans[i]);
    62         printf("%d
    ",ans[i]);
    63     }
    64     return 0;
    65 }//by tkys_Austin;
    View Code
  • 相关阅读:
    《高质量C/C++》读书笔记
    刚刚从网易搬过来了 ,以后就在这安家落户喽
    别让男孩为你哭泣
    EXT综合训练
    liferay中使用自己的数据库
    liferay环境搭建
    第七课,Extjs中常用表单介绍与应用二
    配电管理地理信息系统解决方案
    liferay学习第一站
    第九课,Extjs数据处理
  • 原文地址:https://www.cnblogs.com/Damitu/p/8167738.html
Copyright © 2020-2023  润新知