Luogu 3943 星空
很妙的题。
首先我们发现区间操作不太好弄,我们想办法把它转化成单点操作,这样子处理的办法会多一点。
方法当然是差分了。
定义差分数组$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 星空的更多相关文章
- noip模拟10[入阵曲·将军令·星空](luogu)
对于这次考试来说,总体考得还是不错的 就是有一个小问题,特判一定要判对,要不然和不判一样,甚至错了还会挂掉30分 还有一个就是时间分配问题,总是在前几个题上浪费太多时间,导致最后一个题完全没有时间思考 ...
- 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 ...
- 使用canvas绘制一片星空
效果图 五角星计算方式 代码 <body style="margin:0px;padding:0px;width:100%;height:100%;overflow:hidden;&q ...
- Luogu 魔法学院杯-第二弹(萌新的第一法blog)
虽然有点久远 还是放一下吧. 传送门:https://www.luogu.org/contest/show?tid=754 第一题 沉迷游戏,伤感情 #include <queue> ...
- luogu p1268 树的重量——构造,真正考验编程能力
题目链接:http://www.luogu.org/problem/show?pid=1268#sub -------- 这道题费了我不少心思= =其实思路和标称毫无差别,但是由于不习惯ACM风格的题 ...
- [luogu P2170] 选学霸(并查集+dp)
题目传送门:https://www.luogu.org/problem/show?pid=2170 题目描述 老师想从N名学生中选M人当学霸,但有K对人实力相当,如果实力相当的人中,一部分被选上,另一 ...
- [luogu P2647] 最大收益(贪心+dp)
题目传送门:https://www.luogu.org/problem/show?pid=2647 题目描述 现在你面前有n个物品,编号分别为1,2,3,--,n.你可以在这当中任意选择任意多个物品. ...
- HDU 3943 K-th Nya Number(数位DP)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3943 题目大意:求出区间 (P,Q] 中找到第K个满足条件的数,条件是该数包含X个4和Y个7 Samp ...
- Luogu 考前模拟Round. 1
A.情书 题目:http://www.luogu.org/problem/show?pid=2264 赛中:sb题,直接暴力匹配就行了,注意一下读入和最后一句话的分句 赛后:卧槽 怎么只有40 B.小 ...
随机推荐
- 剑指offer--9.字符串的排列
next_permutation(),还是那个feel ------------------------------------------------------------------------ ...
- unity 四元数, 两行等价的代码
Vector3 tmpvc; 1. tmpvc = Quaternion.Euler (new Vector3 (0, 30, 0)) * new Vector3 (0, 0, 1); 2. tmpv ...
- mysql1130远程连接没有权限的解决方法
网上查了半天,终于解决 远程连接没有权限的原因有两种,一个是因为mysql的限制,一个是防火墙的限制. ,解决防火墙限制: 在mysql服务主机上将防火墙关闭或者在防火墙高级设置里面加入出入站规则,加 ...
- mysqldumpslow使用说明。
mysql慢查询日志分析工具mysqldumpslow. 常用的方法: mysqldumpslow -s c -t 10 /var/run/mysqld/mysqld-slow.log # 取出使用最 ...
- inndb索引原理
###详解b+树如上图,是一颗b+树,关于b+树的定义可以参见B+树,这里只说一些重点,浅蓝色的块我们称之为一个磁盘块,可以看到每个磁盘块包含几个数据项(深蓝色所示)和指针(黄色所示),如磁盘块1包含 ...
- c++运行时决定数组大小 variable-length array
本文由Suzzz原创,发布于 http://www.cnblogs.com/Suzzz/p/4117431.html,转载请保留此声明 variable-length array是C99添加的一个特性 ...
- 技术总监Sycx的故事
其实我在各种演讲里,线下吹牛里面无数次提及过他,讲过他的故事,但是总还是没有任何一次认认真真的详细讲过,所以,今天就讲讲他的故事吧. Sycx是福建漳州人,我经常开玩笑说,你生于一个著名的骗子之乡,为 ...
- Mybatis-Spring包学习
MyBatis-Spring包用来将MyBatis无缝整合到Spring中.使用这个类库中的类, Spring将会加载必要的MyBatis工厂类和Session类. 这个类库也提供一个简单的方式来注入 ...
- Doubango简介-sip
Welcome Android http://code.google.com/p/imsdroid/ http://code.google.com/p/imsdroid/source/browse/# ...
- POJ 1276 Cash Machine(单调队列优化多重背包)
Cash Machine Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 38986 Accepted: 14186 De ...