[置顶] [模拟考试题][神题]Star Sky[状压DP][BFS][差分]
2017-10-24 21:58
369 查看
题意:
给你n个排成一排的灯,0代表开着,1代表关着,有k盏开着的灯。现在你有m种不同长度的电线,可以使得leni那么长的区间反转(0变1,1变0)。现在问你使得整个区间的灯全部开着的最少的操作数。
N <= 40000 K <= 8 M <= 64
真心神题。首先我们观察到序列上的操作都是对于一整段区间而言的,自然想到差分(自然个鬼啊!!),我们将序列用异或差分,然后对一个区间的取反操作变成了对端点的取反。满足条件的序列是全为0的。k很小,就想到在k上做文章。
分析差分序列上的操作:
1.前面有一个1后面有一个0:分别取反变成1 0,相当于1移到了0的位置上。
2.前1后1:将他们同时取反就可以接近目标序列
取反操作的前提是两个bit位相差的距离存在于m个len中,但是同样的,多次移动操作可以构造出合法距离来消掉1
所以想到以每一个差分序列上的1为起点,跑BFS处理它到达其他的1的最小操作数(到达了便消除了)
O(nm)建边
然后用状压DP找到消除1的最优操作顺序
真心神题。模型转化太强了。
首先你得把区间操作转化为差分,并且要想到最终状态给我们的启示——消掉1,然后还要想到用BFS处理距离,然后还要想到用状压处理操作顺序。接近省选题了吧。真心好题。%%%%%出题人
总复杂度O(nm + nmk + k * 2 ^ 2k) (状压没有处理好我T了4个点至今未解决)
给你n个排成一排的灯,0代表开着,1代表关着,有k盏开着的灯。现在你有m种不同长度的电线,可以使得leni那么长的区间反转(0变1,1变0)。现在问你使得整个区间的灯全部开着的最少的操作数。
N <= 40000 K <= 8 M <= 64
真心神题。首先我们观察到序列上的操作都是对于一整段区间而言的,自然想到差分(自然个鬼啊!!),我们将序列用异或差分,然后对一个区间的取反操作变成了对端点的取反。满足条件的序列是全为0的。k很小,就想到在k上做文章。
分析差分序列上的操作:
1.前面有一个1后面有一个0:分别取反变成1 0,相当于1移到了0的位置上。
2.前1后1:将他们同时取反就可以接近目标序列
取反操作的前提是两个bit位相差的距离存在于m个len中,但是同样的,多次移动操作可以构造出合法距离来消掉1
所以想到以每一个差分序列上的1为起点,跑BFS处理它到达其他的1的最小操作数(到达了便消除了)
O(nm)建边
然后用状压DP找到消除1的最优操作顺序
真心神题。模型转化太强了。
首先你得把区间操作转化为差分,并且要想到最终状态给我们的启示——消掉1,然后还要想到用BFS处理距离,然后还要想到用状压处理操作顺序。接近省选题了吧。真心好题。%%%%%出题人
总复杂度O(nm + nmk + k * 2 ^ 2k) (状压没有处理好我T了4个点至今未解决)
#include <bits/stdc++.h> using namespace std; const int N = 40005; int n, k, m, val[1 << 17], a , b , len , head , top, dis[20] , pos[20], f[1 << 17]; struct Node { int y, nxt; Node() { } Node( int y, int nxt ) : y(y), nxt(nxt) { } } e[N * 129]; void Adde( int x, int y ) { e[++top] = Node(y, head[x]), head[x] = top; e[++top] = Node(x, head[y]), head[y] = top; } int h, t, que ; void Bfs( int st, int num ) { h = t = 0; memset(dis[num], 0x3f, sizeof(dis[num])); dis[num][st] = 0; que[++t] = st; while(h < t) { int u = que[++h]; for(int i = head[u]; i; i = e[i].nxt) { int v = e[i].y; if(dis[num][v] != 0x3f3f3f3f) continue; dis[num][v] = dis[num][u] + 1; que[++t] = v; } } } int Dfs( int sta ) { if(sta == 0) return 0; if(f[sta] != -1) return f[sta]; f[sta] = 0x3f3f3f3f; int tmp = sta - ((sta) & (-sta)), cur = tmp, num1 = val[sta & (-sta)]; while(cur) { if(dis[num1][pos[val[cur & (-cur)]]] != 0x3f3f3f3f) f[sta] = min(f[sta], Dfs(tmp - (cur & (-cur))) + dis[num1][pos[val[cur & (-cur)]]]); cur -= cur & (-cur); } return f[sta]; } int main() { cin >> n >> k >> m; for(int i = 1; i <= 16; ++i) val[1 << (i - 1)] = i; for(int i = 1, x; i <= k; ++i) scanf( "%d", &x ), a[x] = 1; for(int i = 1; i <= m; ++i) scanf( "%d", &len[i] ); for(int i = 0; i <= n; ++i) { b[i] = a[i] ^ a[i + 1]; for(int j = 1; j <= m; ++j) if(i + len[j] <= n) Adde(i, i + len[j]); } int cnt = 0, sit = 0; for(int i = 0; i <= n; ++i) if(b[i]) Bfs(i, ++cnt), pos[cnt] = i; memset(f, -1, sizeof(f)); sit = (1 << cnt) - 1; printf( "%d\n", Dfs(sit) ); return 0; } /* 5 2 2 1 5 3 4 */
相关文章推荐
- [置顶] 模拟求解迷宫问题(DFS+BFS)
- hdu 1026 bfs(数组模拟,路径输出)
- 陕西驾驶员模拟考试
- jzoj3929【NOIP2014模拟11.6】创世纪(图论,bfs,贪心)
- 【省选模拟试题】压力 点双连通分量缩点+树上差分
- 九度OJ 1456 胜利大逃亡(模拟+BFS)
- COCI模拟考试心得体会
- Codeforces Round #408 (Div. 2) 思维,模拟,DP, 多点BFS
- Gym - 100543D Wheels 模拟|BFS|签到
- poj Pots(BFS)(路径记录)(模拟)
- hdu 非常可乐(BFS)(模拟)
- [考试] [NOIP模拟] [2017-11-01] 极其良(e)心的一次考试
- 驾照模拟考试所得。
- 藏文驾驶考试模拟软件
- hdu 5336 XYZ and Drops(模拟十滴水游戏bfs)
- 特长生模拟——09年东莞特长生考试
- uva12112 - Iceman BFS模拟 启发式搜索
- 特长生模拟——12年东莞市特长生考试
- Android的SwipeToDismiss第三方开源框架模拟QQ对话列表侧滑删除,置顶,将头像图片圆形化处理。
- 1109 NOIP 模拟考试