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个垃圾的坐标,这个人要捡完所有的 ...
随机推荐
- OO_JAVA_表达式求导
OO_JAVA_表达式求导_第一弹 ---------------------------------------------------表达式提取部分 词法分析 首先,每一个表达式内部都存在不可 ...
- Asp.net Core C#进行筛选、过滤、使用PredicateBuilder进行动态拼接lamdba表达式树并用作条件精准查询,模糊查询
在asp.net core.asp.net 中做where条件过滤筛选的时候写的长而繁琐不利于维护,用PredicateBuilder进行筛选.过滤.LInq配合Ef.core进行动态拼接lamdba ...
- 2021.9.17考试总结[NOIP模拟55]
有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...
- MyBatis源码分析(八):设计模式
Mybatis中用到的设计模式 1. 建造者(Builder)模式: 表示一个类的构建与类的表示分离,使得同样的构建过程可以创建不同的表示.建造者模式是一步一步创建一个复杂的对象,他只允许用户只通过指 ...
- c++中virtual 虚函数
转载: https://www.cnblogs.com/weiyouqing/p/7544988.html 在面向对象的C++语言中,虚函数(virtual function)是一个非常重要的概念. ...
- 转载:使用Xilinx IP核进行PCIE开发学习笔记(一)简介篇
https://zhuanlan.zhihu.com/p/32786076 最近接触到一个项目,需要使用PCIE协议,项目要求完成一个pcie板卡,最终可以通过电脑进行通信,完成电脑发送的指令.这当中 ...
- 最近公共祖先 牛客网 程序员面试金典 C++ Python
最近公共祖先 牛客网 程序员面试金典 C++ Python 题目描述 有一棵无穷大的满二叉树,其结点按根结点一层一层地从左往右依次编号,根结点编号为1.现在有两个结点a,b.请设计一个算法,求出a和b ...
- Codeforces Round #747 (Div. 2)题解
谢天谢地,还好没掉分,还加了8分,(8分再小也是加啊)前期刚开始有点卡,不过在尽力的调整状态之后,还是顺利的将前面的水题过完了,剩下的E2和F题就过不去了,估计是能力问题,自己还是得认真补题啦. E2 ...
- Harbour.Space Scholarship Contest 2021-2022 (Div. 1 + Div. 2) Editorial题解
A 略,发现只有当末尾为9时才满足条件.. B 简单模拟,注意数组大小!!! C 简单模拟. D 比较暴力的一个做法就是每次找一个开始匹配的起始点,然后每次不同时向后跳2就行了. 注意这里最后还要判断 ...
- hdu 1166 敌兵布阵(单点更新,区间查询)
题意: N个工兵营地.工兵营地里的人数分别为:a1,a2,....aN Add i,j:第i个工兵营地里增加j人 Sub i,j:第i个工兵营地里减少j人 Query i,j:查询第i个第j个工兵营地 ...