Codeforces 1188D - Make Equal(dp)
首先我们考虑枚举最后这 \(n\) 个数变成的值 \(v\),那么需要的操作次数即为 \(\sum\limits_{i=1}^n\text{bitcnt}(v-a_i)\),其中 \(\text{bitcnt}(x)\) 为 \(x\) 二进制中 \(1\) 的个数。
这样似乎不太好直接求,不过不难发现这个 \(v\) 一定是 \(\ge\max\{a_i\}\) 的,因此我们考虑转而枚举 \(x=v-\max\{a_i\}\),我们记 \(b_i=\max\{a_j\}-a_i\),那么操作次数又可写为 \(\sum\limits_{i=1}\text{bitcnt}(b_i+x)\)。
显然最优方案下的 \(x\) 必然 \(< 2^{60}\),否则我们总可以找到某一位 \(y\ge 60\) 满足 \(x\) 的 \(2^y\) 为 \(1\),此时考虑令 \(x\leftarrow x-2^y\),答案不会变得更劣。因此我们考虑按位决策,即先考虑 \(x\) 二进制下的最低位,再考虑二进制下的次低位,以此类推。对于 \(x\) 的每一位 \(2^p\),它对答案产生的影响显然就是满足 \(a_i+x\) 的 \(2^p\) 位为 \(1\) 的 \(i\) 的个数,考虑这个个数的影响因素,显然这东西会受到以下三点的影响:
- 每个 \(a_i\) 的 \(2^p\) 位上的值
- \(x\) 的 \(2^p\) 位上的值
- \(a_i+x\) 在 \(2^{p-1}\) 位是否产生了进位
第一点显然开个桶记录一下就行了,第二点就直接枚举 \(x\) 的 \(2^p\) 位是 \(0\) 还是 \(1\) 并分别计算一下即可。棘手的地方在于第三点,共 \(2^n\) 个状态,如果简简单单将其放入 \(dp\) 状态中那连暴力都跑不过,完全不能接受。
不过注意到我们所加的数 \(x\) 是相同的。稍微想想就能知道,\(a_i\bmod 2^p\) 越大的肯定越容易产生进位。因此倘如我们将所有 \(a_i\) 按 \(a_i\bmod 2^p\) 从小到大排序,产生进位的 \(a_i\) 必定是一段后缀。也就是说只要知道有多少个 \(a_i+x\) 在 \(2^{p-1}\) 位产生了进位,就能知道是哪些 \(a_i\) 产生了进位。因此我们设 \(dp_{i,j}\) 表示考虑了前 \(i\) 位,当前位有 \(j\) 个产生进位的最小 \(1\) 的个数,考虑转移,我们假设已经确定了 \(x\) 的前 \(i\) 位,有 \(j\) 个数产生进位,那么按照 \(a_t+x\) 是否在 \(2^i\) 位产生进位,以及 \(a_t\) 的 \(2^{i+1}\) 位的取值可分为 \(4\) 类:
- \(a_t+x\) 在 \(2^i\) 位产生了进位且 \(a_t\) 的 \(2^{i+1}\) 位为 \(1\)
- \(a_t+x\) 在 \(2^i\) 位产生了进位且 \(a_t\) 的 \(2^{i+1}\) 位为 \(0\)
- \(a_t+x\) 在 \(2^i\) 位没有产生进位且 \(a_t\) 的 \(2^{i+1}\) 位为 \(1\)
- \(a_t+x\) 在 \(2^i\) 位没有产生进位且 \(a_t\) 的 \(2^{i+1}\) 位为 \(0\)
我们枚举 \(x\) 的 \(2^{i+1}\) 位是什么,那么
- \(x\) 的 \(2^{i+1}\) 位为 \(0\),那么第一类数会产生进位,第二、三类数 \(2^{i+1}\) 位为 \(1\),贡献随便算
- \(x\) 的 \(2^{i+1}\) 位为 \(1\),那么第一、二、三类数会产生进位,第一、四类数 \(2^{i+1}\) 位为 \(1\)。
时间复杂度 \(n\log^2n\)。
const int MAXB=60;
const int MAXN=1e5;
int n,ord[MAXN+5];ll a[MAXN+5],b[MAXN+5];
int dp[MAXB+5][MAXN+5],sum[MAXN+5][2];
int main(){
scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
sort(a+1,a+n+1);for(int i=1;i<=n;i++) a[i]=a[n]-a[i];
memset(dp,63,sizeof(dp));dp[0][0]=0;
for(int i=0;i<=MAXB;i++){
memset(sum,0,sizeof(sum));
for(int j=1;j<=n;j++) b[j]=a[j]&((1ll<<i)-1);
for(int j=1;j<=n;j++) ord[j]=j;
sort(ord+1,ord+n+1,[](int x,int y){return b[x]<b[y];});
for(int j=1;j<=n;j++){
sum[j][0]=sum[j-1][0];sum[j][1]=sum[j-1][1];
sum[j][a[ord[j]]>>i&1]++;
}
for(int j=0;j<=n;j++){
int cst=sum[n-j][1]+sum[n][0]-sum[n-j][0],carry=sum[n][1]-sum[n-j][1];
chkmin(dp[i+1][carry],dp[i][j]+cst);
cst=sum[n-j][0]+sum[n][1]-sum[n-j][1],carry=n-sum[n-j][0];
chkmin(dp[i+1][carry],dp[i][j]+cst);
}
} printf("%d\n",dp[MAXB+1][0]);
return 0;
}
Codeforces 1188D - Make Equal(dp)的更多相关文章
- Codeforces Gym101341K:Competitions(DP)
http://codeforces.com/gym/101341/problem/K 题意:给出n个区间,每个区间有一个l, r, w,代表区间左端点右端点和区间的权值,现在可以选取一些区间,要求选择 ...
- codeforces 711C Coloring Trees(DP)
题目链接:http://codeforces.com/problemset/problem/711/C O(n^4)的复杂度,以为会超时的 思路:dp[i][j][k]表示第i棵数用颜色k涂完后bea ...
- codeforces#1154F. Shovels Shop (dp)
题目链接: http://codeforces.com/contest/1154/problem/F 题意: 有$n$个物品,$m$条优惠 每个优惠的格式是,买$x_i$个物品,最便宜的$y_i$个物 ...
- Codeforces 1051 D.Bicolorings(DP)
Codeforces 1051 D.Bicolorings 题意:一个2×n的方格纸,用黑白给格子涂色,要求分出k个连通块,求方案数. 思路:用0,1表示黑白,则第i列可以涂00,01,10,11,( ...
- Codeforces 1207C Gas Pipeline (dp)
题目链接:http://codeforces.com/problemset/problem/1207/C 题目大意是给一条道路修管道,相隔一个单位的管道有两个柱子支撑,管道柱子高度可以是1可以是2,道 ...
- Codeforces 704C - Black Widow(dp)
Codeforces 题目传送门 & 洛谷题目传送门 u1s1 感觉这种题被评到 *2900 是因为细节太繁琐了,而不是题目本身的难度,所以我切掉这种题根本不能说明什么-- 首先题目中有一个非 ...
- Codeforces 682B New Skateboard(DP)
题目大概说给一个数字组成的字符串问有几个子串其代表的数字(可以有前导0)能被4整除. dp[i][m]表示字符串0...i中mod 4为m的后缀的个数 通过在i-1添加str[i]字符转移,或者以st ...
- Codeforces 543D Road Improvement(DP)
题目链接 Solution 比较明显的树形DP模型. 首先可以先用一次DFS求出以1为根时,sum[i](以i为子树的根时,满足要求的子树的个数). 考虑将根从i变换到它的儿子j时,sum[i]产生的 ...
- Codeforces 543C Remembering Strings(DP)
题意比较麻烦 见题目链接 Solution: 非常值得注意的一点是题目给出的范围只有20,而众所周知字母表里有26个字母.于是显然对一个字母进行变换后是不影响到其它字符串的. 20的范围恰好又是常见状 ...
随机推荐
- 【c++ Prime 学习笔记】第9章 顺序容器
一个容器是特定类型对象的集合 顺序容器中元素的顺序与其加入容器的位置对应 关联容器中元素的顺序由其关联的关键字决定,关联容器分为有序关联容器和无序关联容器 所有容器类共享公有接口,不同容器按不同方式扩 ...
- Redis:学习笔记-02
Redis:学习笔记-02 该部分内容,参考了 bilibili 上讲解 Redis 中,观看数最多的课程 Redis最新超详细版教程通俗易懂,来自 UP主 遇见狂神说 4. 事物 Redis 事务本 ...
- (转载)gcc -l参数和-L参数
-l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库文件名有什么关系呢?就拿数学库来说,他的库名是m,他的库文件名是libm.so,很容易看出,把库文件名的头lib和尾.so ...
- inline hook原理和实现
inline hook是通过修改函数执行指令来达到挂钩的.比如A要调用B,但人为地修改执行流程导致A调用了C,C在完成了自己的功能后,返回B再执行. 修改这段指令前首先要获取修改权限 由于要修改的代码 ...
- matlab与python scipy.signal中 freqs freqz 中w,什么时候是角频率,什么时候是真实的工程中使用的采样频率Hz,如何转化
matlab与python scipy.signal中的freqs,freqz频率分析函数,输出的w,有时候是角频率,有时候是真实频率,容易搞混,这里对比一下. 0. 精要总结: 1) freqs: ...
- 简单理解函数声明(以signal函数为例)
这两天遇到一些声明比较复杂的函数,比如signal函数,那我们先简单说说signal函数的用法:(参考<c陷阱与缺陷>) [signal:几乎所有c语言程序的实现过程中都要用到signal ...
- k8s入坑之路(10)kubernetes coredns详解
概述 作为服务发现机制的基本功能,在集群内需要能够通过服务名对服务进行访问,那么就需要一个集群范围内的DNS服务来完成从服务名到ClusterIP的解析. DNS服务在kubernetes中经历了三个 ...
- EDG夺冠!用Python分析22.3万条数据:粉丝都疯了!
一.EDG夺冠信息 11月6日,在英雄联盟总决赛中,EDG战队以3:2战胜韩国队,获得2021年英雄联盟全球总决赛冠军,这个比赛在全网各大平台也是备受瞩目: 1.微博热搜第一名,截止2021-11-1 ...
- 多层pcb线路板的制作流程
PCB制作第一步是整理并检查pcb多层线路板布局(Layout).电路板制作工厂收到PCB设计公司的CAD文件,由于每个CAD软件都有自己独特的文件格式,所以深圳PCB板厂会转化为一个统一的格式Ger ...
- shiro550反序列化分析
拖了很久的shiro分析 漏洞概述 Apache Shiro <= 1.2.4 版本中,加密的用户信息序列化后存储在Cookie的rememberMe字段中,攻击者可以使用Shiro的AES加密 ...