原题是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. html5视频video积累

    又是好几个月没有写东西,还是太懒散了~必须要教育下自己罗~ 这次做了个播放视频的移动H5,之前没有仔细玩过,好好记录下基本知识,还有遇到的一些坑,方便之后再次遇见后进行解决 一.基本 video标签在 ...

  2. fiddler抓包

    1.fiddler安装 下载exe安装文件,傻瓜式安装 2.fiddler配置 点击Tools -->Telerik Fiddler Options -->Https,进入以下对话框 Ht ...

  3. 利用HTML5开发Android笔记(下篇)

    资源来自于www.mhtml5.com 杨丰盛老师成都场的PPT分享 一个很简明的demo 可以作为入门基础 学习的过程中做了点笔记 整理如下 虽然内容比较简单 但是数量还是比较多的 所以分了3篇 ( ...

  4. 【phpcms-v9】前台content模块中pc标签的调用说明

    内容模块PC标签调用说明 模块名:content 模块提供的可用操作 操作名 说明 lists 内容数据列表 relation 内容相关文章 hits 内容数据点击排行榜 category 内容栏目列 ...

  5. freemarker实现第一个HelloWorld

    第一步:引入freemarker jar包 第二步:创建templates下的test01.ftl 第三步:在web.xml下 第四步:编写后台代码 package com.wisezone.test ...

  6. vector的简单运用(士兵队列训练问题)

    某部队进行新兵队列训练,将新兵从一开始按顺序依次编号,并排成一行横队,训练的规则如下:从头开始一至二报数,凡报到二的出列,剩下的向小序号方向靠拢,再从头开始进行一至三报数,凡报到三的出列,剩下的向小序 ...

  7. linux开发核心理解

    目录 授权 致谢 序言 更新纪录 导读 如何写作科技文档 I. 气候 1. GUI? CLI? 2. UNIX 缩写风格 3. 版本号的迷雾 4.   Vim 还是 Emacs 5.   DocBoo ...

  8. java服务覆盖率统计 jacoco ant

    ● 下载jacoco.exec.jacocoant.jar.jacocoagent.jar ● jvm启动参数中添加(tomcat服务原理一样) JACOCO_OPTS=JAVA_OPTS=" ...

  9. QrCode C#生成二维码 及JavaScript生成二维码

    一 C#的二维码    示例: class Program { static void Main(string[] args) { QrEncoder qrEncoder = new QrEncode ...

  10. 机器学习:线性回归法(Linear Regression)

    # 注:使用线性回归算法的前提是,假设数据存在线性关系,如果最后求得的准确度R < 0,则说明很可能数据间不存在任何线性关系(也可能是算法中间出现错误),此时就要检查算法或者考虑使用其它算法: ...