Codeforces 题目传送门 & 洛谷题目传送门

一个远古场的 *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+差分转化)的更多相关文章

  1. codeforces#1215E. Marbles(状压DP)

    题目大意:给出一个由N个整数组成的序列,通过每次交换相邻的两个数,使这个序列的每个相同的数都相邻.求最小的交换次数. 比如给出序列:1 2 3 2 1 ,那么最终序列应该是 1 1 2 2 3 ,最小 ...

  2. codeforces 11D(状压dp)

    传送门:https://codeforces.com/problemset/problem/11/D 题意: 求n个点m条边的图里面环的个数 题解: 点的范围只有19,很容易想到是状压. dp[sta ...

  3. 4.26 省选模拟赛 T3 状压dp 差分求答案

    LINK:T3 比较好的题目 考试的时候被毒瘤的T2给搞的心态爆炸 这道题连正解的思路都没有想到. 一看到题求删除点的最少个 可以使得不连通. 瞬间想到最小割 发现对于10分直接跑最小割即可. 不过想 ...

  4. 【模拟8.11】星空(差分转化,状压DP,最短路)

    一道很好的题,综合很多知识点. 首先复习差分:      将原来的每个点a[i]转化为b[i]=a[i]^a[i+1],(如果是求和形式就是b[i]=a[i+1]-a[i]) 我们发现这样的方便在于我 ...

  5. codeforces Diagrams & Tableaux1 (状压DP)

    http://codeforces.com/gym/100405 D题 题在pdf里 codeforces.com/gym/100405/attachments/download/2331/20132 ...

  6. Codeforces Gym 100015F Fighting for Triangles 状压DP

    Fighting for Triangles 题目连接: http://codeforces.com/gym/100015/attachments Description Andy and Ralph ...

  7. 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 ...

  8. Codeforces 544E Remembering Strings 状压dp

    题目链接 题意: 给定n个长度均为m的字符串 以下n行给出字符串 以下n*m的矩阵表示把相应的字母改动成其它字母的花费. 问: 对于一个字符串,若它是easy to remembering 当 它存在 ...

  9. 状压dp Codeforces Beta Round #8 C

    http://codeforces.com/contest/8/problem/C 题目大意:给你一个坐标系,给你一个人的目前的坐标(该坐标也是垃圾桶的坐标),再给你n个垃圾的坐标,这个人要捡完所有的 ...

随机推荐

  1. 更好的 java 重试框架 sisyphus 配置的 2 种方式介绍

    回顾 我们前面学习了 更好的 java 重试框架 sisyphus 入门简介 更好的 java 重试框架 sisyphus 背后的故事 这一节让我们一起学习下 sisyphus 基于函数式的配置和注解 ...

  2. UltraSoft - Beta - Scrum Meeting 9

    Date: May 25th, 2020. Scrum 情况汇报 进度情况 组员 负责 今日进度 q2l PM.后端 记录Scrum Meeting Liuzh 前端 用户忘记密码界面初稿完成 Kkk ...

  3. 使用cerebro可视化ElasticSearch集群信息

    使用cerebro可视化ElasticSearch集群信息 一.背景 二.安装步骤 1.下载并解压 2.配置cerebro 3.启动 cerebro 4.启动界面 三.注意事项 四.参考文档 一.背景 ...

  4. 基于Vue的工作流项目模块中,使用动态组件的方式统一呈现不同表单数据的处理方式

    在基于Vue的工作流项目模块中,我们在查看表单明细的时候,需要包含公用表单信息,特定表单信息两部分内容.前者表单数据可以统一呈现,而后者则是不同业务的表单数据不同.为了实现更好的维护性,把它们分开作为 ...

  5. 算法:拉丁方阵(Latin Square)

    拉丁方阵(英语:Latin square)是一种 n × n 的方阵,在这种 n × n 的方阵里,恰有 n 种不同的元素,每一种不同的元素在同一行或同一列里只出现一次.以下是两个拉丁方阵举例: 拉丁 ...

  6. word-break-ii leetcode C++

    Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each ...

  7. C#写TXT文档

    //C#写TXT文档 String strDir = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAs ...

  8. zabbix 自定义监控项,监控tomcat访问量

    uv:访客量.每个独立上网电脑视为一位访客.pv:访问量.页面浏览量或者点击量,访客每访问一次记录一次. 1.创建文件 /home/zabbix/pvuv_number.sh [ #/bin/bash ...

  9. Linux&C———进程间通信

    管道和有名管道 消息队列 共享内存 信号 套接字 由于进程之间的并不会像线程那样共享地址空间和数据空间,所以进程之间就必须有自己特有的通信方式,这篇博客主要介绍自己了解到的几种进程之间的通信方式,内容 ...

  10. 【Python+postman接口自动化测试】(4)HTTP 协议

    前言 HTTP:超文本传输协议,是用于从WWW服务器传输超文本到本地浏览器的传输协议. HTTP协议是一种无状态协议,主要包含请求和相应两大部分. 请求(Request) get请求示范: GET h ...