传送门

观察题目数据,发现 k ≤ 8 ,可能可以从这里入手解决问题

考虑状态压缩

但是我们每次操作都会让一连串的序列改变,而序列的每个状态都是必须要知道的

很麻烦,所以考虑如何把一段区间表示地简单一些

差分,把原序列转化成差分序列,原序列亮为0,暗为1,差分时用上一个数异或下一个数

那么原数列中一整段的数翻转在差分序列中就变成了几个数的变化

比如我们把第 l 到 r 的数翻转在差分序列中就是把第 l 个数翻转,第 r+1 个数翻转

在差分序列中的任意状态下都是这样

然后考虑结束状态,显然结束状态在差分序列中所有 1 都被翻转成 0

然后考虑翻转一段区间后差分序列状态的变化,显然翻转的两点至少一个点要包含1

不然只会让 1 越来越多,显然不会更优

考虑一个点为 1 的情况,1 变 0,另一个点的 0 变 1

其实就相当于 1 和 0 交换位置,相当于 1 走了长度为区间长度的路程(r-l+1)           l + (r-l+1) = r+1

如果翻转区间的两点都为 1,那么翻转后它们都变为 0

其实相当于一个 1 走到另一个 1 的位置,然后它们互相抵消了

因为初始 1 的数量最多为 2k 个,而且只会越来越少,所以可以考虑状压DP

用BFS预处理出每一个 1 和其他的 1 抵消的最少步数

然后就直接DP转移就好了,转移和 noip2016 愤怒的小鸟 基本一样

设 p [ i ] [ j ] 表示第 i 个 1 和第 j 个 1 抵消的最少步数,那么

f [ i|(1<<j)|(1<<k) ] = min ( f [ i|(1<<j)|(1<<k) ],f [ i ] + p [ j ] [ k ] )

并且因为从左往右第一个 1 迟早要被消去,所以 j 就固定为状态 i 从左往右第一个 1,然后只要枚举 k 就好了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
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=,M=4e5+;
int n,m,K;
int b[];
int pos[N],tot;
int dis[N][M],p[N][N];
bool vis[M];
queue <int> q;
void pre_BFS()//BFS预处理每个1到所有其他1位置的最少步数
{
int x,t; memset(dis,,sizeof(dis)); memset(p,,sizeof(p));
for(int i=;i<=tot;i++)//枚举每个1
{
memset(vis,,sizeof(vis));
q.push(pos[i]); vis[pos[i]]=; dis[i][pos[i]]=;//初始状态
while(!q.empty())
{
x=q.front(); q.pop();
for(int j=;j<=m;j++)
{
t=x+b[j]; if(t>n+||vis[t]) continue; //往后走,注意t>n+1才不能走
dis[i][t]=dis[i][x]+; q.push(t); vis[t]=;
}
for(int j=;j<=m;j++)
{
t=x-b[j]; if(t<=||vis[t]) continue; //往前走
dis[i][t]=dis[i][x]+; q.push(t); vis[t]=;
}
}
for(int j=;j<=tot;j++) if(i!=j) p[i][j]=dis[i][pos[j]]; //处理p数组
}
}
int f[<<],c[M],d[M];
int main()
{
int a;
n=read(); K=read(); m=read();
for(int i=;i<=K;i++)
a=read(),c[a]=;
for(int i=;i<=m;i++) b[i]=read();
for(int i=;i<=n+;i++) d[i]=c[i-]^c[i];
for(int i=;i<=n+;i++) if(d[i]) pos[++tot]=i;//求出差分序列中每个1的位置
pre_BFS();
memset(f,,sizeof(f)); f[]=;
int mx=(<<tot)-,cnt;
for(int i=;i<mx;i++)
{
cnt=;
for(int j=;j<tot;j++) cnt+=(i>>j)&;
if(cnt&) continue;//判断如果状态有奇数个一,那么怎么消都消不掉
for(int j=;j<tot;j++)//找到第一个1
{
if((i>>j)&) continue;
for(int k=j+;k<tot;k++)//枚举其他的1
if(!((i>>k)&)) f[i|(<<j)|(<<k)]=min(f[i|(<<j)|(<<k)],f[i]+p[j+][k+]);//注意如果不能走,p不要设太大,可能爆int
break;//找到后就break掉
}
}
printf("%d",f[mx]);
return ;
}

P3943 星空的更多相关文章

  1. 洛谷P3943 星空

    洛谷P3943 星空 题目背景 命运偷走如果只留下结果, 时间偷走初衷只留下了苦衷. 你来过,然后你走后,只留下星空. 题目描述 逃不掉的那一天还是来了,小 F 看着夜空发呆. 天上空荡荡的,没有一颗 ...

  2. 洛谷 P3943 星空

    题目背景 命运偷走如果只留下结果, 时间偷走初衷只留下了苦衷. 你来过,然后你走后,只留下星空. 题目描述 逃不掉的那一天还是来了,小 F 看着夜空发呆. 天上空荡荡的,没有一颗星星——大概是因为天上 ...

  3. [洛谷P3943]:星空(DP+最短路)

    题目传送门 题目背景 命运偷走如果只留下结果, 时间偷走初衷只留下了苦衷.你来过,然后你走后,只留下星空. 题目描述 逃不掉的那一天还是来了,小$F$看着夜空发呆.天上空荡荡的,没有一颗星星——大概是 ...

  4. 洛谷P3943星空

    啦啦啦啦——又是五月天的歌,题目传送门 这道题比之前两道真的不是同一级别的,这里我这个蒟蒻也讲不清,不如看下这位大佬的吧,他的写的已经非常清楚了:Z-Y-Y-S,这里我就只放下我的代码,也是按照这位大 ...

  5. P3943 星空 区间异或差分

    \(\color{#0066ff}{ 题目描述 }\) 逃不掉的那一天还是来了,小 F 看着夜空发呆. 天上空荡荡的,没有一颗星星--大概是因为天上吹不散的乌云吧. 心里吹不散的乌云,就让它在那里吧, ...

  6. 洛谷P3943 星空——题解

    一道很好的锻炼思维难度的题,如果您能在考场上直接想出来的话,提高组450分以上就没问题了吧.(别像作者一样看了好几篇题解才勉强会) 先提取出题目大意:给定一个长度n<=40000的01串,其中1 ...

  7. 题解 P3943 星空

    题解 一道思维量巨大的题,很烧脑 考虑异或差分,设 \(d_i=a_i\;\;xor\;\;a_{i-1}\),那么对于翻转 \(a_i\sim a_j\) 就相当于 \(b_i\) 和 \(b_{j ...

  8. 差分数组 and 树上差分

    差分数组 定义 百度百科中的差分定义 //其实这完全和要讲的没关系 qwq 进去看了之后是不是觉得看不懂? 那我简单概括一下qwq 差分数组de定义:记录当前位置的数与上一位置的数的差值. 栗子 容易 ...

  9. 2019.2-2019.3 TO-DO LIST

    DP P2723 丑数 Humble Numbers(完成时间:2019.3.1) P2725 邮票 Stamps(完成时间:2019.3.1) P1021 邮票面值设计(完成时间:2019.3.1) ...

随机推荐

  1. 基于:Hadoop 2.6.0-cdh5.4.0 hive1.1.0 HBase 1.0.0-cdh5.4.0 关键配置文件

    core-site.xml <configuration> <property> <name>fs.defaultFS</name> <value ...

  2. WPA密码攻击宝典

    原则:密码以8-10位为主.11位仅限于当地手机号.一般人的多年用数字做密码的习惯和心理,先数 字.再字母,或数字.字母重复几遍,字符几乎全用小写,所以淘汰大写及"~!@#$%^&* ...

  3. JAVA中的垃圾回收机制以及其在android开发中的作用

    http://blog.csdn.net/xieqibao/article/details/6707519 这篇文章概述了JAVA中运行时数据的结构,以及垃圾回收机制的作用.在后半部分,描述了如何检测 ...

  4. JavaScript问题01 js代码放在header和body的区别

    1 body和header中JavaScript执行的时机 1.1 header中 放在header中的javascript代码会进行预加载(即:在页面加载之前就会进行),所以需调用才执行的脚本或事件 ...

  5. 关于c#分支语句和分支嵌套还有变量的作用域。

    分支语句: if....else if....else 必须以 if  开头 后面加括号写入需要判断的内容. 举个栗子说明一下 if (bool类型(比较表达式))  //  他会判断括号内的条件是否 ...

  6. jQuery选择器和选取方法.RP

    我们已经使用了带有简单Css选择器的jQuery选取函数:$().现在是时候深入了解jQuery选择器语法,以及一些提取和扩充选中元素集的方法了. 一.jQuery选择器 在CSS3选择器标淮草案定义 ...

  7. 3.内网渗透之reGeorg+Proxifier

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAxIAAAE2CAIAAAB6BDOVAAAgAElEQVR4Aey9Z5Aex3X327MRGVzkRH ...

  8. 带参宏定义和inline修饰的内联函数

    带参宏定义和inline修饰的内联函数都是在编译时,用函数体替换掉宏调用或函数调用.这样用的好处是减少调用函数所花费的时间. 例如: 算法导论在讲到堆排序时说的,好的堆排序实现一般是把Left(i), ...

  9. Codeforces 917B MADMAX (DP+博弈)

    <题目链接> 题目大意:给定一个DAG图,其中图的边权是给定的字符所对应的ascii码,现在A先手,B后手,每次沿DAG图走一步,但是第i次走的边权一定要大于等于第i-1次走的边权(这里是 ...

  10. 网络模拟工具Clumsy

    Clumsy 是一款小巧而功能强大的开源弱网模拟工具,它能在windows平台下人工造成不稳定的网络状况,方便你调试应用程序在极端网络状况下的表现. 你可以选择 clumsy 提供的功能来有目的性的调 ...