zoukankan      html  css  js  c++  java
  • noi.ac309 Mas的童年

    题目链接

    题面

    题目描述

    (Mas)完成了一天的工作,走在回家的路上,看着路边的景色,他想起来自己的童年。

    许许多多的记忆交错,丝丝缕缕的牵扯着(Mas)

    在回忆的深处,(Mas)想起来了一个常常在幼儿园玩的游戏。

    (n)个小朋友一起排成一排,然后小朋友们会一起开始跳舞。

    聪明的(Mas)发现,每个小朋友都有自己的高兴程度,对于第(i)个小朋友,他的高兴程度是(ai)

    当一排高兴程度分别为(b_1,b_2,…,b_k)(k)个小朋友跳舞的时候,他们会产生(b1 otimes b2 otimes ⋯otimes bk)的愉悦值。

    但是(Mas)觉得不够尽兴,于是他决定让小朋友们从某个位置分开,让原本一排的队伍分成两排,从而使两排新队伍的愉悦值加起来最大,当然,是有可能不分成两排的。

    具体的,对于一排kk个小朋友,他们的高兴程度分别是(b_1,b_2,…,b_k),(Mas)会找到位置(iin [0,k),使得(b1otimes ⋯otimes bi)+(bi+1otimes ⋯otimes bk))最大。

    回想起这个游戏的(Mas)决定再来玩一下这个游戏,于是他想起来了某一天排成一排的(n)个小朋友的高兴程度(a1,a2,…,an)对于(i=1..n)(Mas)希望求出前(i)个小朋友排成的队伍中通过拆分成两个队伍能够得到的最大愉悦值的和是多少。

    输入

    第一行一个正整数(n)表示小朋友的数量。

    第二行(n)个整数,表示(a_{1..n})

    输出

    一行(n)个整数表示答案。

    思路

    读完拉么长的题面。发现他其实就是对于每个位置要求这个东西

    [max{(S_i otimes S_j)+ S_j} ]

    其中(S_i)表示前(i)个元素的异或和。

    然后根据(a+b = aotimes b + (a & b) imes 2)

    这个证明的话很显然:因为异或相当于不进位的加法。用(&)可以求出需要进位的位置。然后乘二在相加就可以啦。

    这样我们就可以把要求的式子变成这个样子

    [max{S_i otimes S_j otimes S_j + (S_i otimes S_j & S_j) imes 2} ]

    [=max{S_i + (S_i otimes S_j & S_j) imes 2} ]

    因为(S_i)是确定的,只要让(S_i otimes S_j & S_j)最大就行了。

    然后我们按位思考。对于二进制下的第(k)位。如果(S_i)的这一位为(1),那么不管(S_j)这一位是什么,肯定都无法将答案的这一位变成(1)

    所以我们就想要让(S_i)(0)的那些位置尽可能变成(1)

    对于每个(S_j),我们将他和他的子集标记一下。然后贪心的从高位到低位将(S_i)(0)的位置变为(1).

    并且查看当前的答案是不是之前标记过。

    具体看代码吧

    代码

    /*
    * @Author: wxyww
    * @Date:   2019-03-30 08:10:10
    * @Last Modified time: 2019-03-31 08:31:43
    */
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    const int N = 2000000 + 100;
    ll read() {
    	ll x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9') {
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9') {
    		x=x*10+c-'0';
    		c=getchar();
    	}
    	return x*f;
    }
    int s[N];
    bool vis[N];
    void ins(int x) {
    	if(vis[x]) return;
    	vis[x] = true;
    	for(int i = 0;i <= 20;++i) {
    		if((x >> i) & 1)	ins(x - (1 << i));
    	}
    }
    int solve(int x) {
    	int ret = 0;
    	int k = x ^ ((1 << 21) - 1);
    	for(int i = 20;i >= 0;--i) 
    		if(((k >> i) & 1) && vis[(ret + (1 << i))]) 
    			ret += (1 << i);
    	return ret;
    }
    int main() {
    	int n = read();
    	for(int i = 1;i <= n;++i) s[i] = s[i - 1] ^ read();
    
    	vis[0] = true;
    
    	for(int i = 1;i <= n;++i) {
    		printf("%d ",solve(s[i]) * 2 + s[i]);
    		ins(s[i]);
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    python+django+vue搭建前后端分离项目
    PC网页js调用本地应用程序
    mysql-connetor-c 自动创建数据库、数据库表的命令
    JMeter设置响应数据的编码格式
    VS2013常用快捷键
    WPF 实现 TextBox 只能输入数字并且不能使用拷贝功能
    WPF 先显示登录成功,验证成功后显示主窗口
    ListControl 设置表格行高与字体
    win7 删除多余启动项的方法
    设置编辑工具UltraEdit的背景色为护眼颜色
  • 原文地址:https://www.cnblogs.com/wxyww/p/noiac309.html
Copyright © 2011-2022 走看看