『8.25 模拟赛』外卖 (atcoder 100e)
Posted fang-hao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了『8.25 模拟赛』外卖 (atcoder 100e)相关的知识,希望对你有一定的参考价值。
题目描述
众所周知,(cky)喜欢点外卖。
已知可选的商品有(n)种,(cky)由于胃容量问题只能点两份(不能一种点两份)。(cky)要在防止营养过剩的情况下选择美味度最高的搭配。
具体的,对于每第(i)个商品,(i)正好是其营养成分,(s_i)表示其美味度(商品从(0)开始编号)。
对于每种搭配((a,b)),其营养程度为((a|b)其中(|)表示二进制下的按位或),其美味度为(s_a+s_b)。
即(cky)要选择满足(a|bleq k)中,(s_a+s_b)最大的((a,b))。
由于(cky)好久没去体检,所以不知道能接受多少营养成分,所以希望对于每一种(k)都求出答案。
为了送分,(n)均可以表示为(2^N),其中(N)为整数。
解题思路
首先,因为是或运算,所以我们可以想到高维前缀和。
我们分别维护对于每一个k的最大值和次大值,那么我们就可以利用高维前缀和的方法进行转移。
我们假设dp[ i ][ 0 / 1 ]表示当前数值i的最大值在原序列中的位置(0),和次大值的位置(1),那么我们就可以枚举给i在二进制下的所有为0的位置选择一个加1,这样就可以转移到一个新的状态tmp,(tmp=i+(1<<j))这样就可以由i推到tmp,我么只要比较i和tmp的最大值和次大值,以下有三种情况:
1)tmp的最大值小于i的最大值:那么我们显然是要把tmp的次大值变成tmp的最大值,把i的最大值变成tmp的最大值。
2)tmp的次大值小于i的最大值并且tmp的最大值和i的最大值取的不是同一个位置:那么tmp的次大值变成i的最大值。
2)tmp的次大值小于i的次大值:那么把tmp的次大值改成i的次大值
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=(1<<21);
int n;
int a[maxn],dp[maxn][2];
int main(){
scanf("%d",&n);
for(register int i=0;i<(1<<n);i++){
scanf("%d",&a[i]);
dp[i][0]=i;
}
for(register int i=0;i<(1<<n);i++){
for(register int j=0;i+(1<<j)<=(1<<n);j++){
if(!(i&(1<<j))){
int tmp=i|(1<<j);
if(a[dp[tmp][0]]<a[dp[i][0]]){
dp[tmp][1]=dp[tmp][0];
dp[tmp][0]=dp[i][0];
}
else if(a[dp[tmp][1]]<a[dp[i][0]]&&dp[tmp][0]!=dp[i][0]){
dp[tmp][1]=dp[i][0];
}
else if(a[dp[tmp][1]]<a[dp[i][1]]){
dp[tmp][1]=dp[i][1];
}
}
}
}
int ans=0;
for(register int i=1;i<(1<<n);i++){
ans=max(ans,a[dp[i][0]]+a[dp[i][1]]);
printf("%d
",ans);
}
}
以上是关于『8.25 模拟赛』外卖 (atcoder 100e)的主要内容,如果未能解决你的问题,请参考以下文章