• 【BZOJ3508】开灯


    【BZOJ3508】开灯

    题面

    bzoj

    题解

    其实变为目标操作和从目标操作变回来没有区别,我们考虑从目标操作变回来。

    区间整体翻转(( ext{Xor};1))有点难受,我们考虑将这个操作放在差分数组上,也就是说令(a)为原数组,(c)为差分数组,(c_i=a_{i-1} ext{Xor};a_i)

    那么我们就相当于让差分数组上的数全变为(0),而一次操作就相当于让一对(1)消掉或一对(0,1)位置互换。

    而两个(1)在其他位置消掉和在某个(1)的位置消掉是没有区别的,多个(1)也一样,所以我们可以直接(bfs)预处理每对点消掉的贡献。

    而差分数组最多(2K)(1),状压每个点有没有被消掉即可。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue> 
    using namespace std;
    
    inline int gi() {
        register int data = 0, w = 1;
        register char ch = 0;
        while (ch != '-' && (ch > '9' || ch < '0')) ch = getchar();
        if (ch == '-') w = -1 , ch = getchar();
        while (ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
        return w * data;
    } 
    const int INF = 0x3f3f3f3f; 
    const int MAX_N = 40005, MAX_M = 105; 
    int N, K, M; 
    int b[MAX_M]; 
    bool used[MAX_N], g[MAX_N]; 
    int st[30], tp;
    int cost[30][30], dep[MAX_N]; 
    
    queue<int> que; 
    void bfs(int s, int *dis) { 
    	memset(dep, 0, sizeof(dep));
    	dep[s] = 1;
    	que.push(s);
    	while (!que.empty()) {
    		int x = que.front(); que.pop();
    		for (int i = 1; i <= M; i++) {
    			if (x + b[i] <= N && !dep[x + b[i]]) dep[x + b[i]] = dep[x] + 1, que.push(x + b[i]); 
    			if (x - b[i] >= 1 && !dep[x - b[i]]) dep[x - b[i]] = dep[x] + 1, que.push(x - b[i]); 
    		} 
    	} 
    	for (int i = 0; i < tp; i++) dis[i] = dep[st[i]] - 1; 
    } 
    int f[1 << 20]; 
    int main () {
    #ifndef ONLINE_JUDGE 
    	freopen("cpp.in", "r", stdin); 
    #endif 
    	int Q = gi(); 
    	while (Q--) { 
    		memset(used, 0, sizeof(used)); tp = 0; 
    		N = gi() + 1, K = gi(), M = gi(); 
    		for (int i = 1; i <= K; i++) used[gi()] = 1; 
    		for (int i = 1; i <= M; i++) b[i] = gi(); 
    		for (int i = 1; i <= N; i++) g[i] = used[i] ^ used[i - 1]; 
    		for (int i = 1; i <= N; i++) if (g[i]) st[tp++] = i; 
    		for (int i = 0; i < tp; i++) bfs(st[i], cost[i]); 
    		memset(f, 0x3f, sizeof(f)); 
    		f[0] = 0; 
    		for (int S = 0; S < (1 << tp) - 1; S++) { 
    			for (int i = 0; i < tp; i++) { 
    				if (S >> i & 1) continue; 
    				for (int x = i + 1; x < tp; x++) { 
    					if ((S >> x & 1) == 0 && (cost[i][x] != -1)) { 
    						int tmp = (S | (1 << i) | (1 << x)); 
    						f[tmp] = min(f[tmp], f[S] + cost[i][x]); 
    					} 
    				} 
    				break; 
    			} 
    		} 
    		printf("%d
    ", f[(1 << tp) - 1] == INF ? -1 : f[(1 << tp) - 1]);
    	} 
    	return 0; 
    }
    
  • 相关阅读:
    CCF_2014_09_2_画图
    计蒜课_等和分隔子集
    计蒜客_合法分数的组合
    读构建之法的读书笔记
    四则运算及感想
    psp 第二周
    第二周 词频统计
    历年作品点评
    四人小组项目
    品读《构建之法》及几个问题的提出
  • 原文地址:https://www.cnblogs.com/heyujun/p/11765915.html
Copyright © 2020-2023  润新知