[NOI2017]游戏

经典2-sat。

题意:有n个变量,每个变量有三个取值。但是有的变量的一个取值被限制为不能取。

只有不超过8个变量的取值未被限制,即三个都能取。

有m个约束条件,形如:若第i个变量取了a则第j个变量必须取b。

输出一种取值方案。无解输出-1。

n<=50000,m<=100000

好,假装是3-sat的东西.......

一个朴素想法是枚举未被限制的变量的取值,150000*3^8,超时。

然而正解就这样从TLE中浮出水面:假设未被限制的变量都被限制了,那么枚举限制了哪一个,两次即可覆盖所有情况。

时间复杂度150000*2^8,AC。

(在UOJ上面会97)

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 
  5 const int N = 50010;
  6 
  7 struct Edge {
  8     int nex, v;
  9 }edge[N << 2]; int top;
 10 
 11 struct ORDER {
 12     int a, b, c, d;
 13 }ask[N << 1];
 14 
 15 int e[N * 3], dfn[N * 3], low[N * 3], tot, stk[N * 3], t, space[10], sp;
 16 int scc_cnt, fr[N * 3], use[N], m, n;
 17 bool in_stk[N * 3];
 18 char s[N], bb[2], dd[2];
 19 
 20 inline void add(int x, int y) {
 21     top++;
 22     edge[top].nex = e[x];
 23     edge[top].v = y;
 24     e[x] = top;
 25     return;
 26 }
 27 
 28 void tarjan(int x) {
 29     dfn[x] = low[x] = ++tot;
 30     in_stk[x] = 1;
 31     stk[++t] = x;
 32     for(int i = e[x]; i; i = edge[i].nex) {
 33         int y = edge[i].v;
 34         if(!dfn[y]) {
 35             tarjan(y);
 36             low[x] = std::min(low[x], low[y]);
 37         }
 38         else if(in_stk[y]) {
 39             low[x] = std::min(low[x], dfn[y]);
 40         }
 41     }
 42     if(low[x] == dfn[x]) {
 43         scc_cnt++;
 44         int y;
 45         do {
 46             y = stk[t--];
 47             in_stk[y] = 0;
 48             fr[y] = scc_cnt;
 49         } while(y != x);
 50     }
 51     return;
 52 }
 53 
 54 inline int _(int x) { // opposite
 55     int i = x;
 56     while(i > n) {
 57         i -= n;
 58     }
 59     for(int j = 0; j < 3; j++) {
 60         if(i + j * n != x && use[i] != j + 1) {
 61             return i + j * n;
 62         }
 63     }
 64     return -0x3f3f3f3f;
 65 }
 66 
 67 inline void out() {
 68     for(int i = 1; i <= n; i++) {
 69         int x = use[i] == 1 ? i + n : i;
 70         int y = _(x);
 71         x = (fr[x] < fr[y]) ? x : y;
 72         putchar('A' + ((x - 1) / n));
 73     }
 74     return;
 75 }
 76 
 77 inline bool solve() {
 78     for(int i = 1; i <= m; i++) {  //  a.b -> c.d
 79         int x = ask[i].a + (ask[i].b - 1) * n;
 80         int y = ask[i].c + (ask[i].d - 1) * n;
 81         if(use[ask[i].a] == ask[i].b) {
 82             continue;
 83         }
 84         if(use[ask[i].c] == ask[i].d) {
 85             add(x, _(x));
 86         }
 87         else {
 88             add(x, y);
 89             add(_(y), _(x));
 90         }
 91     }
 92 
 93     for(int i = 1; i <= n; i++) {
 94         for(int j = 1; j <= 3; j++) {
 95             if(use[i] != j && !dfn[i + (j - 1) * n]) {
 96                 tarjan(i + (j - 1) * n);
 97             }
 98         }
 99     }
100 
101     for(int i = 1; i <= n; i++) {
102         int x = use[i] == 1 ? i + n : i;
103         int y = _(x);
104         if(fr[x] == fr[y]) {
105             return 0;
106         }
107     }
108     return 1;
109 }
110 
111 inline void clear() {
112     top = 0;
113     tot = 0;
114     scc_cnt = 0;
115     memset(dfn, 0, sizeof(dfn));
116     memset(low, 0, sizeof(low));
117     memset(e, 0, sizeof(e));
118     return;
119 }
120 
121 int main() {
122     int d;
123     scanf("%d%d", &n, &d);
124     scanf("%s", s + 1);
125     for(int i = 1; i <= n; i++) {
126         if(s[i] == 'x') {
127             space[++sp] = i;
128         }
129         else {
130             use[i] = (s[i] - 'a') + 1;
131         }
132     }
133     scanf("%d", &m);
134     for(int i = 1; i <= m; i++) {
135         scanf("%d%s%d%s", &ask[i].a, bb, &ask[i].c, dd);
136         ask[i].b = bb[0] - 'A' + 1;
137         ask[i].d = dd[0] - 'A' + 1;
138     }
139 
140     int lm = (1 << d);
141     for(int i = 0; i < lm; i++) {
142         if(i) {
143             clear();
144         }
145         for(int j = 0; j < d; j++) {
146             use[space[j + 1]] = ((i >> j) & 1) + 1;
147         }
148         if(solve()) {
149             out();
150             return 0;
151         }
152     }
153     printf("-1");
154     return 0;
155 }
AC代码

 

posted @ 2018-10-04 20:52  garage  阅读(132)  评论(0编辑  收藏  举报