题目大意
现在有
N
个位置,每个位置要填入一个
N,M≤105
解题思路
我们一步步从题目的约束中挖掘性质。
首先,相邻的两个数的差的大于等于2,那么1的傍边只能是3,4。2的旁边只能是4。3的旁边只能是1。4的旁边只能是1,2。我们发现1,2和3,4的填入肯定是交错的,就是说奇数位一定是1,2,偶数位一定是3,4(反过来也行,没什么区别)。那么对于一个点就只有两个选择,那么这就非常像2-SAT了。
那么我们就按2-SAT的方式连边,比如奇数位的2就一定要像右边的偶数位的4连一条边,因为选了2就只能在旁边选4。类似的我们就解决了相邻的性质。对于 M 条约数也很简单,我们同样要分奇数位和偶数位讨论,因为他们之间不可能相同。那么我们只需在奇偶性相同的位置连一条交叉的双向边(比如3连到4,4连到3)。最后跑一次2-SAT判是否有解就可以了。
提示:解决相邻的约束时,只用从前面往后面连边。因为我们做2-SAT时是默认了做完了前
程序
十分丑的代码。。。
//YxuanwKeith
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 2e5 + 5;
int N, M, c, Test, S[MAXN];
int tot, Last[MAXN], Next[MAXN * 40], Go[MAXN * 40];
bool mark[MAXN];
void Link(int a, int b) {
Next[++ tot] = Last[a], Last[a] = tot, Go[tot] = b;
}
void Read(int &Now) {
char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
Now = 0;
while (ch >= '0' && ch <= '9') Now = Now * 10 + ch - '0', ch = getchar();
}
bool Dfs(int x) {
int y = (x & 1) ? (x + 1) : (x - 1);
if (mark[y]) return 0;
if (mark[x]) return 1;
mark[x] = 1;
S[c ++] = x;
for (int p = Last[x]; p; p = Next[p])
if (!Dfs(Go[p])) return 0;
return 1;
}
bool Solve() {
memset(mark, 0, sizeof mark);
memset(Last, 0, sizeof Last);
tot = 0;
Read(N), Read(M);
for (int i = 1; i < N; i ++) {
int a = i, b = i + 1;
Link(a * 2, b * 2 - 1);
}
for (int i = 1; i <= M; i ++) {
int Num;
Read(Num);
if (Num > 4) return 0;
static int _0[3], _1[3];
_0[0] = _1[0] = 0;
for (int j = 0; j < Num; j ++) {
int Now;
Read(Now);
if (Now & 1) _0[++ _0[0]] = Now; else _1[++ _1[0]] = Now;
}
if (_0[0] > 2 || _1[0] > 2) return 0;
if (_0[0] > 1) {
Link(_0[1] * 2, _0[2] * 2 - 1);
Link(_0[1] * 2 - 1, _0[2] * 2);
Link(_0[2] * 2, _0[1] * 2 - 1);
Link(_0[2] * 2 - 1, _0[1] * 2);
};
if (_1[0] > 1) {
Link(_1[1] * 2, _1[2] * 2 - 1);
Link(_1[1] * 2 - 1, _1[2] * 2);
Link(_1[2] * 2, _1[1] * 2 - 1);
Link(_1[2] * 2 - 1, _1[1] * 2);
}
}
for (int i = 1; i <= N * 2; i += 2) {
if (!mark[i] && !mark[i + 1]) {
c = 0;
if (!Dfs(i)) {
while (c > 0) mark[S[-- c]] = 0;
if (!Dfs(i + 1)) return 0;
}
}
}
return 1;
}
int main() {
int Test;
scanf("%d", &Test);
for (int i = 1; i <= Test; i ++) {
if (Solve()) printf("approved\n"); else
printf("rejected\n");
}
}