Codeforces 79D - Password(状压 dp+差分转化)
一个远古场的 *2800,在现在看来大概 *2600 左右罢(
不过我写这篇题解的原因大概是因为这题教会了我一个套路罢(
首先注意到每次翻转的是一个区间,那么我们可以考虑它的差分序列(这就是这题教会我的套路,碰到区间操作有关的问题不妨考虑它的差分序列,这样可将影响多个元素的区间操作转化为 \(2\) 个单点操作,其实第一次碰见这个套路是在这个题,可是由于当时比较 naive 没能及时补题并整理这些方法),那么每次操作显然是将差分序列上两个单点进行翻转,而翻转的两个单点的距离恰好等于操作区间的长度,于是现在问题转化为:你有一个初始为 \(0\) 的长度为 \(n+1\) 的序列 \(a\),你可以选择两个单点并将它们的状态翻转,满足这两个单点的距离属于某个集合 \(S\),要求最少多少次操作将序列变为给定序列 \(a'\)。
考虑怎样解决转化后的问题,首先取两个单点并翻转显然是不影响 \(1\) 的个数的奇偶性的,因此如果 \(1\) 的个数是奇数那直接 \(-1\) 即可,否则显然我们会将这些 \(1\) 两两配对,对于同一对中的两个位置 \(x,y\),我们会以如下方式让 \(x,y\) 上的数都变为 \(0\):
重复以下步骤若干次:
- 选择一个长度 \(l\in S\) 并将 \(x\) 与 \(x+l\) 或 \(x-l\) 同时翻转,这样即可将 \(x\) 上的 \(1\) 转移到 \(x+l\) 或 \(x-l\) 上。
直到 \(x+l=y\lor x-l=y\)
我们记 \(d_{x,y}\) 为将 \(x,y\) 上的数变为 \(0\) 的最小步骤,那么显然我们可以以每个 \(1\) 为起点进行一遍 BFS 求出所有 \(d_{x,y}\)。注意到此题 \(k\le 10\),因此差分序列上 \(1\) 的个数 \(\le 20\),故考虑状压 \(dp\),\(dp_S\) 表示将 \(S\) 中的 \(1\) 变为 \(0\) 的最小代价,转移就枚举两个 \(x,y\notin S\) 然后 \(dp_{S\cup\{x\}\cup\{y\}}\leftarrow dp_S+d_{x,y}\) 即可。
据说有更优秀的二分图最小权完美匹配的做法?i 了 i 了,可惜我懒癌爆发懒得写了
复杂度 \(2^kk^2+nmk\),其中 \(k=20\)。
const int MAXN=1e4;
const int MAXM=100;
const int MAXK=20;
const int MAXP=1<<20;
const int INF=0x3f3f3f3f;
int n,k,m,a[MAXN+5],b[MAXN+5],l[MAXM+5],id[MAXN+5],pos[MAXK+5];
int dis[MAXN+5],d[MAXK+5][MAXK+5],cnt;
void bfs(int s){
queue<int> q;memset(dis,-1,sizeof(dis));
dis[s]=d[id[s]][id[s]]=0;q.push(s);
while(!q.empty()){
int x=q.front();q.pop();
if(id[x]) d[id[s]][id[x]]=dis[x];
for(int i=1;i<=m;i++){
if(x+l[i]<=n+1){
if(!~dis[x+l[i]]) dis[x+l[i]]=dis[x]+1,q.push(x+l[i]);
} if(x-l[i]>=1){
if(!~dis[x-l[i]]) dis[x-l[i]]=dis[x]+1,q.push(x-l[i]);
}
}
}
}
int dp[MAXP+5];
int main(){
scanf("%d%d%d",&n,&k,&m);
for(int i=1,x;i<=k;i++) scanf("%d",&x),a[x]=1;
for(int i=1;i<=m;i++) scanf("%d",&l[i]);
for(int i=1;i<=n+1;i++) b[i]=a[i]^a[i-1];
for(int i=1;i<=n+1;i++) if(b[i]) id[i]=++cnt,pos[cnt]=i;
memset(d,63,sizeof(d));
for(int i=1;i<=n+1;i++) if(id[i]) bfs(i);
memset(dp,63,sizeof(dp));dp[0]=0;
// printf("%d\n",cnt);
// for(int i=1;i<=cnt;i++) for(int j=1;j<=cnt;j++)
// printf("%d%c",d[i][j]," \n"[j==cnt]);
for(int i=0;i<(1<<cnt);i++){
if(dp[i]>=INF) continue;
for(int j=1;j<=cnt;j++) for(int l=1;l<j;l++)
if((~i>>j-1&1)&&(~i>>l-1&1))
chkmin(dp[i|(1<<j-1)|(1<<l-1)],dp[i]+d[j][l]);
} printf("%d\n",(dp[(1<<cnt)-1]>=INF)?-1:dp[(1<<cnt)-1]);
return 0;
}
Codeforces 79D - Password(状压 dp+差分转化)的更多相关文章
- codeforces#1215E. Marbles(状压DP)
题目大意:给出一个由N个整数组成的序列,通过每次交换相邻的两个数,使这个序列的每个相同的数都相邻.求最小的交换次数. 比如给出序列:1 2 3 2 1 ,那么最终序列应该是 1 1 2 2 3 ,最小 ...
- codeforces 11D(状压dp)
传送门:https://codeforces.com/problemset/problem/11/D 题意: 求n个点m条边的图里面环的个数 题解: 点的范围只有19,很容易想到是状压. dp[sta ...
- 4.26 省选模拟赛 T3 状压dp 差分求答案
LINK:T3 比较好的题目 考试的时候被毒瘤的T2给搞的心态爆炸 这道题连正解的思路都没有想到. 一看到题求删除点的最少个 可以使得不连通. 瞬间想到最小割 发现对于10分直接跑最小割即可. 不过想 ...
- 【模拟8.11】星空(差分转化,状压DP,最短路)
一道很好的题,综合很多知识点. 首先复习差分: 将原来的每个点a[i]转化为b[i]=a[i]^a[i+1],(如果是求和形式就是b[i]=a[i+1]-a[i]) 我们发现这样的方便在于我 ...
- codeforces Diagrams & Tableaux1 (状压DP)
http://codeforces.com/gym/100405 D题 题在pdf里 codeforces.com/gym/100405/attachments/download/2331/20132 ...
- Codeforces Gym 100015F Fighting for Triangles 状压DP
Fighting for Triangles 题目连接: http://codeforces.com/gym/100015/attachments Description Andy and Ralph ...
- Codeforces Gym 100610 Problem K. Kitchen Robot 状压DP
Problem K. Kitchen Robot Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/10061 ...
- Codeforces 544E Remembering Strings 状压dp
题目链接 题意: 给定n个长度均为m的字符串 以下n行给出字符串 以下n*m的矩阵表示把相应的字母改动成其它字母的花费. 问: 对于一个字符串,若它是easy to remembering 当 它存在 ...
- 状压dp Codeforces Beta Round #8 C
http://codeforces.com/contest/8/problem/C 题目大意:给你一个坐标系,给你一个人的目前的坐标(该坐标也是垃圾桶的坐标),再给你n个垃圾的坐标,这个人要捡完所有的 ...
随机推荐
- 初学python-day2 字符串格式化1
- [对对子队]会议记录4.20(Scrum Meeting11)
今天已完成的工作 何瑞 工作内容:搭建第三关,添加了运行指令标识 相关issue:搭建关卡2.3 相关签入:4.20签入1 4.20签入2 吴昭邦 工作内容:搭建第三关 相关iss ...
- wpa_supplicant启动出错rfkill: Cannot open RFKILL control device
在板子是调试网络,千辛万苦把wpa_supplicant及其依赖都移植编译进来了,在板子上调试启动的时候启动报错了 D/wpa_supplicant( 1152): wpa_supplicant v2 ...
- 神经网络 感知机 Perceptron python实现
import numpy as np import matplotlib.pyplot as plt import math def create_data(w1=3,w2=-7,b=4,seed=1 ...
- 双栈排序 牛客网 程序员面试金典 C++ Python
双栈排序 牛客网 程序员面试金典 C++ Python 题目描述 请编写一个程序,按升序对栈进行排序(即最大元素位于栈顶),要求最多只能使用一个额外的栈存放临时数据,但不得将元素复制到别的数据结构中. ...
- 接口自动化 - pytest-fixture -scope作用范围
接口自动化-pytest中的fixture - scope 介绍 fixture文章中介绍的比较少,同学们可以去搜索下fixture的详解或者去看看源码 ...
- matlab与python scipy.signal中 freqs freqz 中w,什么时候是角频率,什么时候是真实的工程中使用的采样频率Hz,如何转化
matlab与python scipy.signal中的freqs,freqz频率分析函数,输出的w,有时候是角频率,有时候是真实频率,容易搞混,这里对比一下. 0. 精要总结: 1) freqs: ...
- MyBatis-Plus 快速入门
1.简介 MyBatis-Plus (简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发.提高效率而生. 1.1.特性 无侵入:只做增强不做改变, ...
- VUE的MVVM框架解析
这篇文章主要介绍了MVVM模式中ViewModel和View.Model有什么区别?本文分别解释了它们的功能和作用,然后总结了它之间的区别,需要的朋友可以参考下 Model:很简单,就是业务逻辑相关的 ...
- 这一次,Google 终于对 Web 自动化下手了!
大家好,我是安果! 最近 Google 对 Chrome 进行了一次比较大的更新,其中一项是脚本录制回放功能,它可以非常方便我们处理一些自动化场景 我们可以在 Chrome 官网下载 Chrome C ...