原题是CF79D Password

很妙的题。

首先我们发现区间操作不太好弄,我们想办法把它转化成单点操作,这样子处理的办法会多一点。

方法当然是差分了。

定义差分数组$b_i = a_i \^ a_{i + 1}$($b_i$的下标从$0$开始),在这里将$\^$记为异或。

那么$a_i = b_0 \^ b_1 \^ b_2 \^ ... \^ b_i$,如果我们将所有一开始没有点亮的灯记为$1$,而将所有点亮的灯记为$0$,如果要点亮所有灯,那么我们最后要使$\forall i \in [0, n]   \ a_i == 0 $成立,就相当于使$\forall i \in [0, n]   \ b_i == 0 $成立。

这样子我们改一段区间$[l, r]$的时候就相当于把$b_{l - 1}, b_{r}$都异或上$1$。

发现这样子最多不会超过有$2k$个为$1$的位置,直接状压起来。

我们可以推出$dp$了,假设$f_s$表示当前选的$s$集合最少需要多少操作的步数,那么$f_s + cost(i, j)$可以更新$f_{s \cup i \cup j\ (i \notin s,j \notin s)}$。

如果能预处理这个$cost(i, j)$,那么这个转移就可以写成$O(k2^k)$的,顺便一提在本题中写成$O(k^2 * 2^k)$也是能过的。

发现我们在选择点在更新的时候一定至少会选择有一个$0$的去更新(因为更新两个$1$没有意义……)。因此我们如果要更新$i$和$j$,假如$j - i$恰好等于一个可以更新的区间长度,那么只需要一步;但是如果没有怎么办,我们需要“绕路走”,引入一个或多个中间点$k$来使$i$和$j$同时更新,发现这样子所有的$k$都被异或了偶数次,所以最后的结果仍然只有$i$和$j$被更新。

发现了吧,这是一个最短路,预处理的时候对每一个点跑一遍$dij$或者$spfa$即可。

我实现的代码是$O(k^2 * 2^k)$的。

Code:

#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
using namespace std;
typedef pair <int, int> pin; const int N = 1e4 + ;
const int M = ;
const int W = ;
const int S = ( << ) + ;
const int inf = 0x3f3f3f3f; int n, m, K, a[N], b[N], idCnt = , id[W];
int len[M], dis[N], c[W][W], f[S];
bool vis[N]; inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} priority_queue <pin> Q;
void dij(int st) {
memset(dis, 0x3f, sizeof(dis));
memset(vis, , sizeof(vis));
Q.push(pin(dis[st] = , st));
for(; !Q.empty(); ) {
int x = Q.top().second; Q.pop();
if(vis[x]) continue;
vis[x] = ;
for(int i = ; i <= m; i++) {
int y = x + len[i];
if(y <= n && dis[y] > dis[x] + ) {
dis[y] = dis[x] + ;
Q.push(pin(-dis[y], y));
}
y = x - len[i];
if(y >= && dis[y] > dis[x] + ) {
dis[y] = dis[x] + ;
Q.push(pin(-dis[y], y));
}
}
}
} inline void chkMin(int &x, int y) {
if(y < x) x = y;
} int main() {
read(n), read(K), read(m);
for(int pos, i = ; i <= K; i++) read(pos), a[pos] = ;
for(int i = ; i <= m; i++) read(len[i]); for(int i = ; i <= n; i++) b[i] = a[i] ^ a[i + ];
for(int i = ; i <= n; i++)
if(b[i]) id[++idCnt] = i; /* for(int i = 1; i <= idCnt; i++)
printf("%d ", id[i]);
printf("\n"); */ memset(c, 0x3f, sizeof(c));
for(int i = ; i <= idCnt; i++) {
dij(id[i]);
for(int j = ; j <= idCnt; j++)
if(i != j) c[i][j] = dis[id[j]];
} /* for(int i = 1; i <= idCnt; i++, printf("\n"))
for(int j = 1; j <= idCnt; j++)
printf("%d ", c[i][j]); */ memset(f, 0x3f, sizeof(f)); f[] = ;
for(int s = ; s < ( << idCnt); s++) {
if(f[s] == inf) continue;
for(int i = ; i <= idCnt; i++) {
if((s >> (i - )) & ) continue;
for(int j = ; j <= idCnt; j++) {
if((s >> (j - )) & ) continue;
int to = s | ( << (i - )) | ( << (j - ));
chkMin(f[to], f[s] + c[i][j]);
}
}
} int curS = ( << idCnt) - ;
if(f[curS] == inf) puts("-1");
else printf("%d\n", f[curS]);
return ;
}

Luogu 3943 星空的更多相关文章

  1. noip模拟10[入阵曲·将军令·星空](luogu)

    对于这次考试来说,总体考得还是不错的 就是有一个小问题,特判一定要判对,要不然和不判一样,甚至错了还会挂掉30分 还有一个就是时间分配问题,总是在前几个题上浪费太多时间,导致最后一个题完全没有时间思考 ...

  2. SYMBDSNAP_SDK[3943]: Failed to open device: /dev/symbdsnapctl, errno: 2

    在Linux的日志/var/log/message里面看到下面错误信息: Oct 26 09:48:42 xxxxxxx SYMBDSNAP_SDK[3943]: Failed to open dev ...

  3. 使用canvas绘制一片星空

    效果图 五角星计算方式 代码 <body style="margin:0px;padding:0px;width:100%;height:100%;overflow:hidden;&q ...

  4. Luogu 魔法学院杯-第二弹(萌新的第一法blog)

    虽然有点久远  还是放一下吧. 传送门:https://www.luogu.org/contest/show?tid=754 第一题  沉迷游戏,伤感情 #include <queue> ...

  5. luogu p1268 树的重量——构造,真正考验编程能力

    题目链接:http://www.luogu.org/problem/show?pid=1268#sub -------- 这道题费了我不少心思= =其实思路和标称毫无差别,但是由于不习惯ACM风格的题 ...

  6. [luogu P2170] 选学霸(并查集+dp)

    题目传送门:https://www.luogu.org/problem/show?pid=2170 题目描述 老师想从N名学生中选M人当学霸,但有K对人实力相当,如果实力相当的人中,一部分被选上,另一 ...

  7. [luogu P2647] 最大收益(贪心+dp)

    题目传送门:https://www.luogu.org/problem/show?pid=2647 题目描述 现在你面前有n个物品,编号分别为1,2,3,--,n.你可以在这当中任意选择任意多个物品. ...

  8. HDU 3943 K-th Nya Number(数位DP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3943 题目大意:求出区间 (P,Q] 中找到第K个满足条件的数,条件是该数包含X个4和Y个7 Samp ...

  9. Luogu 考前模拟Round. 1

    A.情书 题目:http://www.luogu.org/problem/show?pid=2264 赛中:sb题,直接暴力匹配就行了,注意一下读入和最后一句话的分句 赛后:卧槽 怎么只有40 B.小 ...

随机推荐

  1. 如何用visual studio2013编写简单C语言程序

    vc++6.0 作为经典版本,虽然已经几乎淘汰,但还是有很多的初学者在使用.但当他们使用vs2013时会发现界面和操作和vc++6.0有了极大的不同,不知该如何 操作.随着vs2013的普及,更多人使 ...

  2. THUWC2019 滚粗记

    因为真的滚粗了,所以咕咕咕 膜清华爷 OYJason

  3. CODE FESTIVAL 2017 qual A--C - Palindromic Matrix(模拟所有情况,注意细节)

    个人心得:其实本来这题是有规律的不过当时已经将整个模拟过程都构思出来了,就打算试试,将每个字符和总和用优先队列 装起来,然后枚举每个点,同时进行位置标志,此时需要多少个点的时候拿出最大的和出来,若不满 ...

  4. 四、python沉淀之路--元组

    一.元组基本属性 1.元组不能被修改,不能被增加.不能被删除 2.两个属性 tu.count(22)       #获取指定元素在元组中出现的次数tu.index(22)      #获取指定元素的缩 ...

  5. mysql之 共享表空间与独立表空间、frm,MYD,MYI.idb,par文件说明

    一.共享表空间与独立表空间MySQL5.5默认是共享表空间 ,5.6中,默认是独立表空间. 共享表空间:ibdata1是InnoDB的共享表空间,默认配置是把全部表空间存放到ibdata1中,因此而造 ...

  6. webrtc自带client的视频引擎创建代码走读

    src\webrtc\examples\peerconnection\client\conductor.ccbool Conductor::InitializePeerConnection()1 we ...

  7. PHP:json_encode 保持中文不被转为ASCII码

    echo json_encode(array('黄河之水天上来'),JSON_UNESCAPED_UNICODE);

  8. 蓝桥杯 算法训练 ALGO-126 水仙花

    算法训练 水仙花   时间限制:1.0s   内存限制:256.0MB 水仙花数 问题描述 判断给定的三位数是否 水仙花 数.所谓 水仙花 数是指其值等于它本身 每位数字立方和的数.例 153 就是一 ...

  9. 【转】LTE基本架构

    这篇文章主要介绍LTE的最基础的架构,包括LTE网络的构成,每一个网络实体的作用以及LTE网络协议栈,最后还包括对一个LTE数据流的模型的说明. LTE网络参考模型 这是一张非常有名的LTE架构图,从 ...

  10. Python:内置split()方法

    描述 Python split()通过指定分隔符对字符串进行切片,如果参数num 有指定值,则仅分隔 num 个子字符串 语法 split()方法语法: str.split(str="&qu ...