『8.25 模拟赛』外卖 (atcoder 100e)

题目链接

题目描述

众所周知,\(cky\)喜欢点外卖。

已知可选的商品有\(n\)种,\(cky\)由于胃容量问题只能点两份(不能一种点两份)。\(cky\)要在防止营养过剩的情况下选择美味度最高的搭配。

具体的,对于每第\(i\)个商品,\(i\)正好是其营养成分,\(s_i\)表示其美味度(商品从\(0\)开始编号)。

对于每种搭配\((a,b)\),其营养程度为(\(a|b\)其中\(|\)表示二进制下的按位或),其美味度为\(s_a+s_b\)。

即\(cky\)要选择满足\(a|b\leq 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\n",ans);
    }
}

原文地址:https://www.cnblogs.com/Fang-Hao/p/9535264.html

时间: 2024-08-30 14:24:58

『8.25 模拟赛』外卖 (atcoder 100e)的相关文章

『8.20 模拟赛』旋转的多边形

题目链接戳着里!! 题目描述 解题思路 显然,多边形滚动的时候,指定的点一定是绕着某一个顶点旋转的,旋转的半径就是点到顶点的距离,角度就是顶点所在脚的外角. 如下图所示: 那么我们的问题就转化成了求dis和θ了. dis很简单,只要勾股定理就好了. 那θ呢?也很简单喽,只要链接当前顶点的相邻的两个顶点,运用余弦定理求就好啦,注意一下角度值和弧度制就可以了. (不会余弦定理的小伙伴戳这里==>  Wikipedia & 百度百科) 代码 1 #include<iostream> 2

『8.20 模拟赛』冒泡排序

题目描述 给定n,k,和一个长度为n的序列,请输出这个序列冒泡排序k次之后的结果. 解题思路 我们观察上面给出的伪代码,可以发现这是一段把代码排序成升序的代码,那我们来考虑一下冒牌排序的几个特征. 一个大的数要向右交换,但是一次交换之后就可以换很多位置,所以换一次就不知道跑到哪里去了,所以很难维护. 一个小的数每次最多和它左边的更大的数交换一次,所以一次最多向左边跑一个位置,比大数不知道好维护到那里去了. 进一步思考,k次交换之后,最多可以向左跑k步,也就是说k+1位置的数最远能跑到1的位置上来

『8.21 模拟赛』Victory

题目描述 迟到大王rsw喜欢V这个字母,因为V代表着victory,当一个数字,从左向右数的时候,没有出现过先递减,再递增的情况,就被称作Victory数. 也就是说,这个数字可以是递增的,也可以是递减的,也可以是先递减再递增的,这个过程中可以出现相邻数字相等的情况,但是,就是不能出现过先递减再递增的情况. 问题是:给定n,问:1~n之间有多少个victory数. 解题思路 我们应该一眼就能看出这是一道数位dp题,一开始用3维dp写,状态不够写挂了...后来改用4维就A了. 我们用dp[ i ]

『8.21 模拟赛』技能大赛

题目描述 rsw因为迟到次数太多被列入黑名单,于是被派去参加陕西妇女儿童技能大赛,大赛中共安排了m个比赛项目,算上rsw在内,共有n位选手报名参加本次比赛.(如rsw,zrx,kh,ljm,cky,大耳朵图图,大头儿子等) 经过m场比赛,组委会发现,每个项目,有且仅有两个人实力超群.(比如穿针引线项目,rsw,ljm独领风骚,健美操项目,cky,cjy风姿绰约). 现在,组委会要推选一些人去参加全国比赛,因为每个项目都必须有人擅长,所以推选的这些人,对于每一个项目,至少要有一个人擅长. 已知,选

『8.21 模拟赛』冒泡排序 II

题目描述 前一天的冒泡排序对rsw来说太简单了,所以又有了冒泡排序2,给定n,k,q,问:有多少个不同的1~n的排列,能够使得,冒泡排序k趟后,得到一个几乎正确的序列. 一个几乎正确的序列指的是:它的最长上升子序列的长度至少是n-1. 解题思路 思路就是没有思路.... 昨天刚刚做过一道冒泡排序的题,有一个结论在这里 每个位置上的数最远是由前面的第k个位置转移过来的,并且题目中要求最长上升子序列最短是n-1的长度,所以只有两种情况: 1) 最终是从小到大排序好的 2)最终是从小到大排序好的序列中

『8.24 模拟赛』ranwen的服务器

题目链接戳这里n(*≧▽≦*)n 题目描述 众所周知,ranwen建造出了强大的服务器网,规模十分庞大,有n个服务器,组成一个树形结构,1号点是总站,但是有时候可能会因为主机被回收,机房断电等事故造成服务器各种GG,现在有m个事件,可能为:1.查询x到根路径上第一个已经挂掉的服务器传输路径 2.x到y路径上的服务器传输路径全挂了.(不存在则输出0) 解题思路 上来先是树剖,然而只过了样例,爆0... 题面上提示了正解是并查集,但是并没有想出来,听完题解瞬间懂了.... 并查集,当然最方便的是合并

3.25 模拟赛

T1 题目大意: 给出一个数$n$,求有多少个正回文数对$(p,q)$满足$p+q=n$ 思路: T2 题目大意: 给出一个带边权的完全图,定义树上一个点的权值$f(x)$为其到根的路径上边权的最小值,特别的$f(root)=0$,一个树的权值为所有点的权值和 求每个点的最小权值生成树 思路: 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #

10.25模拟赛

NP(np) Description LYK 喜欢研究一些比较困难的问题, 比如 np 问题. 这次它又遇到一个棘手的 np 问题. 问题是这个样子的: 有两个数 n 和 p, 求 n 的阶乘 对 p 取模后的结果. LYK 觉得所有 np 问题都是没有多项式复杂度的算法的,所以它打算求助即将要参加 noip 的你, 帮帮 LYK 吧! Input ? 输入一行两个整数 n,p. Output 输出一行一个整数表示答案. 数据范围 对于 20%的数据: n,p<=5. 对于 40%的数据: n,

2017.11.25【NOIP提高组】模拟赛A组

2017.11.25[NOIP提高组]模拟赛A组 T1 3467. [NOIP2013模拟联考7]最长上升子序列(lis) T2 3468. [NOIP2013模拟联考7]OSU!(osu) T3 3472. [NOIP2013模拟联考8]匹配(match) T1 有转移方程f[i]=max{f[j]}+1,a[j]<a[i] 可以用线段树+离散化维护这个方程,因为涉及以往状态可以用主席树维护 打太丑爆空间了 Code 1 #include<cstdio> 2 #include<c