原题是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. xsl教程学习笔记

    一 . Hello world 尝试: Hello.xml: <?xml version="1.0" encoding="UTF-8"?> < ...

  2. 2017.11.27 stm8 low power-consumption debugging

    1 STM8L+LCD The STM8L-DISCOVERY helps you to discover the STM8L ultralow power features and todevelo ...

  3. POJ 3071 Football (概率DP)

    概率dp的典型题.用dp[j][i]表示第j个队第i场赢的概率.那么这场要赢就必须前一场赢了而且这一场战胜了可能的对手.这些都好想,关键是怎么找出当前要算的队伍的所有可能的竞争对手?这个用异或来算,从 ...

  4. php是如何工作的

    a:前提条件: apache服务器启动正常工作 b:客户端浏览器在地址栏输入一个程序地栏 按回车发送请求 {请求}http://127.0.0.1/day03/1.php c:apache接收请求,并 ...

  5. centos type.h 编译错误问题

    # ifndef __int8_t_defined # define __int8_t_defined __intN_t (, __QI__); __intN_t (, __HI__); __intN ...

  6. 每天一个linux命令(15):head命令

    版权声明更新:2017-05-19博主:LuckyAlan联系:liuwenvip163@163.com声明:吃水不忘挖井人,转载请注明出处! 1 文章介绍 本文介绍了Linux下面的mv命令. 2. ...

  7. Visualforce入门第三篇_2017.3.2

    Visualforce实现显示Record List(列表) 详细见链接:https://trailhead.salesforce.com/modules/visualforce_fundamenta ...

  8. (1)java8初体验

    很多博客都拿Comparator,我也贴一下吧. java8以前的匿名内部类用来排序. //匿名内部类 @Test public void java8Test() { Person p1 = new ...

  9. Qt中如何用QImage::Format_Indexed8表示灰度图

    QImage *qi = new QImage(data_ptr, width, height, QImage::Format_Indexed8); QVector<QRgb> grayT ...

  10. Mongodb 5节点异地两中心故障转移恢复测试案例

    Mongodb5节点异地两中心故障转移恢复测试案例 架构方式:5节点,主中心(2数据1仲裁),备中心(1数据1仲裁) 1基本情况 操作系统:Red Hat Enterprise Linux Serve ...