Codeforces 1238E. Keyboard Purchase
注意到 $m$ 只有 $20$ ,考虑一下状压 $dp$
设 $f[S]$ 表示当前确定的字符集合为 $S$ ,那么转移就考虑从最右边加入的下一个字符 $c$
那么问题来了,代价如何计算
考虑每次加入一个字符以后对于所有字符间的移动$(c_i,c_{i+1})$产生的代价
那么显然只有当 $c_i \in S$ ,$c_{i+1} \notin S$ 时,移动 $(c_i,c_{i+1})$ 会多经过当前加入的字符的位置,那么需要的时间就会增加 $1$
所以我们可以维护一个 $cnt[i][j]$ 表示 $c_{i}=i,c_{i+1}=j$ 的移动数量
那么每次转移代价可以直接 $m^2$ 枚举所有 $c_{i} \in S$ ,$c_{i+1} \notin S$ 的移动求出
这样复杂度是 $m^2 \cdot 2^m$ 算一下发现达到了 $4 \cdot 10^8$ 级别,时间限制 $1s$,显然很有问题
那么现在有两种选择,优化算代价的速度,或者用信仰直接交复杂度不对的代码
然后你发现信仰是对的,卡着时限是可以过的....比如这位神仙:https://codeforces.com/contest/1238/submission/62149786
四个点 $997ms$ 一个点 $998ms$ $\text{Orz}$
但是我没有信仰
来考虑一下如何快速计算代价,设 $h[S]$ 表示所有 $c_i \in S$ ,$c_{i+1} \notin S$ 的移动的数量
再设 $g[p][S],p \notin S$ 表示 $c_i=p , c_{i+1} \in S$ 的移动的数量
那么有 $h[S] = \sum_{p \in S} g[p][U\text{^}S]$ ,其中 $U$ 是全集
现在考虑计算 $g$ ,如果对于每个 $p,S$ 都枚举所有 $p' \notin S$ 再累加显然太慢了
注意到 $S$ 的子集 $S'$ 的代价 $g[p][S']$ 一定会加入到 $g[p][S]$ 中,那么对于 $S$ 直接枚举某一位选择的 $p'$
设 $S'|(1<<p')=S$,有 $g[p][S]=g[p][S']+cnt[p][p']$
然后现在又有一个小问题,要对所有 $S$ 求出某一个为 $1$ 的位置
考虑树状数组的操作, $x&-x$ 就是 $x$ 的第一位 $1$ 的值
最后维护 $pos[x]$ 表示值为 $x=(1<<p)$ 时的 $p$
然后这一题就解决了,复杂度 $O(m \cdot 2^m)$
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') { if(ch=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=1e5+,M=;
int n,m,cnt[M][M];
int pos[(<<M)+],f[(<<M)+],g[M][(<<M)+],h[(<<M)+];
char s[N];
int main()
{
n=read(),m=read();
scanf("%s",s+);
for(int i=;i<n;i++)
cnt[s[i]-'a'][s[i+]-'a']++,
cnt[s[i+]-'a'][s[i]-'a']++;
for(int i=;i<m;i++) pos[<<i]=i;
memset(f,0x3f,sizeof(f));
int mx=(<<m)-; f[]=;
for(int p=;p<m;p++)
for(int o=;o<mx;o++)
{
if(o&(<<p)) continue;
g[p][o]=g[p][o-(o&-o)]+cnt[p][pos[o&-o]];
}
for(int o=;o<mx;o++)
for(int p=;p<m;p++)
if(o&(<<p)) h[o]+=g[p][mx^o];
for(int o=;o<mx;o++)
for(int p=;p<m;p++)
{
if(o&(<<p)) continue;
f[o^(<<p)]=min(f[o^(<<p)],f[o]+h[o]);
}
printf("%d\n",f[mx]);
return ;
}
Codeforces 1238E. Keyboard Purchase的更多相关文章
- Keyboard Purchase CodeForces - 1238E (状压)
大意: 给定串$s$, 字符集为字母表前$m$个字符, 求一个$m$排列$pos$, 使得$\sum\limits_{i=2}^n|{pos}_{s_{i-1}}-{pos}_{s_{i}}|$最小. ...
- codeforces 831B. Keyboard Layouts 解题报告
题目链接:http://codeforces.com/contest/831/problem/B 题目意思:给出两个长度为26,由小写字母组成的字符串s1和s2,对于给出的第三个字符串s3,写出对应s ...
- CF1238E.Keyboard Purchase 题解 状压/子集划分DP
作者:zifeiy 标签:状压DP,子集划分DP 题目链接:https://codeforces.com/contest/1238/problem/E 题目大意: 给你一个长度为 \(n(n \le ...
- Codeforces 474A Keyboard (水
题目链接:点击打开链接 键盘移位了,问输出相应的字母 #include <cstdio> #include <cstring> char a[105]; char b[3][1 ...
- CodeForces 474A Keyboard (水题)
题意:给定一个键盘,然后一行字母,和一个字符,代表把那一行字母在键盘上左移还是右移一位. 析:没什么好说的,直接暴力就好. 代码如下: #include<bits/stdc++.h> us ...
- Codeforces1238E. Keyboard Purchase(状压dp + 计算贡献)
题目链接:传送门 思路: 题目中的m为20,而不是26,显然在疯狂暗示要用状压来做. 考虑状压字母集合.如果想要保存字母集合中的各字母的顺序,那就和经典的n!的状态的状压没什么区别了,时间复杂度为O( ...
- 【CF1238E】Keyboard Purchase(状压DP,贡献)
题意:有m种小写字符,给定一个长为n的序列,定义编辑距离为序列中相邻两个字母位置差的绝对值之和,其中字母位置是一个1到m的排列 安排一种方案,求编辑距离最小 n<=1e5,m<=20 思路 ...
- CF-diary
(做题方式:瞟题解然后码) 1238E. Keyboard Purchase \(\texttt{Difficulty:2200}\) 题意 给你一个长度为 \(n\) 的由前 \(m\) 个小写字母 ...
- Educational Codeforces Round 74
目录 Contest Info Solutions A. Prime Subtraction B. Kill 'Em All C. Standard Free2play D. AB-string E. ...
随机推荐
- Spring在Thread中注入Bean无效的解决方式
在Spring项目中,有时需要新开线程完成一些复杂任务,而线程中可能需要注入一些服务.而通过Spring注入来管理和使用服务是较为合理的方式.但是若直接在Thread子类中通过注解方式注入Bean是无 ...
- mysql 5.7.19安装
从mysql官网下载的mysql5.7.19免安装版, 安装时出现问题,mysql总是启动不起来,在网上查了下资料,做个记录: .将mysql解压到指定的文件夹 .以管理员身份运行cmd .定位到my ...
- 按Excel的模板导出数据
思路:把Excel模板上传到服务器:然后读取文档,写入数据,另存为新的文件 然后就是导出的时候处理数据定义的字符串,按数据导出:注意读取的数据流要处理下,不然会报异常 public Stream Ge ...
- Qt之QTableWidget
学习QTableWidget就要首先看看QTableView控件(控件也是有”家世“的!就像研究人一样一样的),因为QTableWidget继承于类QTableView. 两者主要区别是QTableV ...
- Python 数字(函数)
Python支持4种不同数值类型: 整型(Int) - 通常被称为是整型或整数,是正或负整数,不带小数点. 长整型(long integers) - 无限大小的整数,整数最后是一个大写或小写的L. 浮 ...
- Mac命令行提示
之前看到一个大神的终端主题好炫,所以自己也想弄一个.看了很多中文的教程都不是很靠谱,效果并没有实现.不能说人家的不对,只能说自己水平有限.后来直接去看 github 上的官方教程,因为是官方嘛~所以肯 ...
- Python打
.智能识别图片物体.这步是智能垃圾分类的魔法核心.原理是人工智能会根据打上标签的海量图片来识别新的图片所归属的分类标签.好奇的读者可能会问,我没学过深度学习啊?我也不会训练模型,怎么办? python ...
- list 字符串拼接效率实验
ist 字符串拼接有多种方法,我就其中常用三种做了实验,实验代码如下: 第一次是为了初始化静态方法,后面的才是效率比较. 结果如下: StringUtils join 方法用的是StringBuild ...
- 本地套接字-本地socket
本地套接字简单应用场景 一 #服务端--简单 import socket import os a='sock_file' if os.path.exists(a): os.remove(a) s=so ...
- time 时间模块的函数调用
时间模块 time 此模块提供了时间相关的函数,且一直可用 时间简介 公元纪年是从公元 0000年1月1日0时开始的 计算机元年是从1970年1月1日0时开始的,此时时间为0,之后每过一秒时间+1 U ...