• [bzoj4945][Noi2017]游戏


    题目大意:有$n$个位置,有三种数,每个位置只可以填一种数,$d(dleqslant8)$个位置有三种选择,其他位置只有两种选择。有一些限制,表示第$i$个位置选了某种数,那么第$j$个位置就只能选规定的数

    输出一组合法的选数方案,无解输出$-1$

    题解:考虑$d=0$的情况,就是$2-sat$的裸题。

    那$d>0$的呢?发现$dleqslant8$,因为跑一次$2-sat$的复杂度是$O(n+m)(nleqslant5 imes10^4,mleqslant10^5)$,好像有很大的空间乱搞?若暴力$dfs$每一位选什么,复杂度是$O(3^8(n+m))approx9.8 imes10^8$,过不了。

    考虑优化,如果枚举$d$个位置不可以填什么,那么就是$1,2;2,3;1,3$,发现前两种已经包含了$1,2,3$三种方案,于是复杂度成了$O(2^8(n+m))approx3.8 imes10^7$。可以承受,于是就过了

    卡点:1.限制条件给的是大写字母,写成小写字母

    ​   2.有一个函数因为调试改成了另一个,最后忘记调回来,花了我$1.5h+$的时间

    C++ Code:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #define maxn 50010
    #define maxm 100010
    int n, nn, D, m, tot;
    int X[10], p[maxn];
    int a[maxm], b[maxm], c[maxm], d[maxm];
    char s[maxn];
    
    int head[maxn << 1], cnt;
    struct Edge {
    	int to, nxt;
    } e[maxm << 1];
    void addE(int a, int b) {
    	e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
    }
    
    int DFN[maxn << 1], low[maxn << 1], idx;
    int S[maxn << 1], top, res[maxn << 1], CNT;
    bool ins[maxn << 1];
    inline int min(int a, int b) {return a < b ? a : b;}
    void tarjan(int x) {
        DFN[x] = low[x] = ++idx; ins[S[++top] = x] = 1;
        int y;
        for (int i = head[x]; i; i = e[i].nxt)
            if (!DFN[y = e[i].to]) tarjan(y), low[x] = std::min(low[x], low[y]);
            else if (ins[y]) low[x] = std::min(low[x], DFN[y]);
        if (DFN[x] == low[x]) {
            CNT++;
            do ins[y = S[top--]] = 0, res[y] = CNT; while (x != y);
        }
    }
    
    void init() {
    	memset(head, 0, sizeof head), cnt = 0;
    	memset(DFN, 0, sizeof DFN), idx = 0;
    	CNT = 0;
    }
    inline bool get(int a, int b) {return b != (a + 1) % 3;}
    inline char reget(int a, int b) {return (b + a + 1) % 3 + 'A';}
    inline int P(int a, int b) {return a << 1 | b;}
    bool work(int T) {
    	init();
    	for (int i = 0; i < D; i++) p[X[i]] = bool(T & 1 << i);
    	for (int i = 0; i < m; i++) {
    		if (p[a[i]] != b[i]) {
    			if (p[c[i]] == d[i]) addE(a[i] << 1 | get(p[a[i]], b[i]), a[i] << 1 | !get(p[a[i]], b[i]));
    			else {
    				addE(a[i] << 1 | get(p[a[i]], b[i]), c[i] << 1 | get(p[c[i]], d[i])),
    				addE(c[i] << 1 | !get(p[c[i]], d[i]), a[i] << 1 | !get(p[a[i]], b[i]));
    			}
    		}
    	}
    	for (int i = 2; i <= nn + 1; i++) {
    		if (!DFN[i]) tarjan(i);
    		if (i & 1) if (res[i] == res[i - 1]) return false;
    	}
    	for (int i = 1; i <= n; i++) printf("%c", reget(res[i << 1] > res[i << 1 | 1], p[i]));
    	return true;
    }
    
    int main() {
    	scanf("%d%d%s", &n, &D, s + 1); nn = n << 1;
    	for (int i = 1; i <= n; i++) {
    		if (s[i] == 'x') X[tot++] = i;
    		p[i] = s[i] - 'a';
    	}
    	scanf("%d", &m);
    	for (int i = 0; i < m; i++) {
    		char B, D;
    		scanf("%d %c %d %c", a + i, &B, c + i, &D);
    		b[i] = B - 'A';
    		d[i] = D - 'A';
    	}
    	int U = 1 << D;
    	for (int i = 0; i < U; i++) if (work(i)) return 0;
    	printf("-1");
    	return 0;
    }
    

      

  • 相关阅读:
    配置OSPF负载分担
    IPv4静态路由与NQA联动
    静态路由实现路由负载分担
    静态路由实现主备备份
    (一)非整数幂情形下的广义牛顿二项式定理
    小小知识点(二十三)被科研人员忽略的ORCID —— 如何注册和使用?意义何在?
    小小知识点(二十二)word 排版技巧大全
    小小知识点(二十一)Mathtype怎么批量更改全文的公式格式
    小小知识点(十九)如何破解安装编辑PDF文本的软件——福昕编辑器和Adobe acrobat DC
    (三十二)5G前传、中传和回传
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9690758.html
Copyright © 2020-2023  润新知