Pre
真的毒瘤题,昨天晚上以为是一道简单的图论题,今天中午没有调出来,晚上我选择看题解发现漏了一种情况。
于是
就花了一晚上调程序。
现在时间(21:31)
Solution
拆点是很容易想到的。
拓扑((Tarjan)应该也可以,没试过)找环。
之后分类。
有一个点在环内就不符合。
若两个点都不在环内,需要对图重建,之后染色判断这两个点是否有父子关系。
不知不觉就快200行代码(以下的代码有删减)。
Code
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define xx first
#define yy second
using namespace std;
const int N = 1000000 + 5, M = N << 1;
int suf[M], n;
int fr[M << 1], to[M << 1], h[M], tot;
inline void add (int u, int v) {
tot++;
fr[tot] = h[u];
to[tot] = v;
h[u] = tot;
}
inline int qian (int x) {
x--;
while (x <= n) {
x += n;
}
return x;
}
inline int hou (int x) {
x++;
while (x > n) {
x -= n;
}
return x;
}
queue<int> Q;
int rd[M];
bool type[M];
inline void Top () {
for (int i = 1; i <= n * 2; ++i) {
if (!rd[i]) {
Q.push (i);
}
}
while (Q.size ()) {
int tmp = Q.front();
Q.pop();
type[tmp] = 1;
rd[suf[tmp]]--;
if (!rd[suf[tmp]]) {
Q.push(suf[tmp]);
}
}
}
int it[M], color[M], cocnt;
bool ins[M], fatin[N];
inline void dfs (int u) {
if (u <= n * 2) {
ins[u] = 1;
}
int ne = u > n ? u - n : u + n;
if (ins[ne]) {
fatin[min (u, ne)] = 1;
}
for (int i = h[u]; i; i = fr[i]) {
if (u > n * 2) {
color[to[i]] = u - n * 2;
}
else {
color[to[i]] = color[u];
}
dfs (to[i]);
}
ins[u] = 0;
}
inline void Rebuild () {
for (int i = 1; i <= n * 2; ++i) {
it[i] = type[i] ^ 1;
type[i] ^= 1;
}
for (int i = 1; i <= n * 2; ++i) {
if (it[i]) {
cocnt++;
for (int j = suf[i]; j != i; j = suf[j]) {
color[j] = cocnt;
it[j] = 0;
}
color[i] = cocnt;
it[i] = 0;
}
}
for (int i = 1; i <= n * 2; ++i) {
if (type[i]) {
continue;
}
if (!type[suf[i]]) {
add (suf[i], i);
}
else{
add (color[suf[i]] + n * 2, i);
}
}
for (int i = 1; i <= cocnt; ++i) {
dfs (n * 2 + i);
}
}
int main () {
memset (type, 0, sizeof (type));
scanf ("%d", &n);
for (int i = 1; i <= n; ++i) {
int tmp;
scanf ("%d", &tmp);
if (tmp == 1) {
suf[i] = hou (i);
suf[i + n] = qian (i);
}
else if (tmp == 2) {
suf[i] = qian (i);
suf[i + n] = hou (i);
}
else if (tmp == 3) {
suf[i] = hou (hou (i));
suf[i + n] = qian (qian (i));
}
else if (tmp == 4) {
suf[i] = qian (qian (i));
suf[i + n] = hou (hou (i));
}
rd[suf[i]]++;
rd[suf[i + n]]++;
}
Top ();
Rebuild ();
int ans = 0;
for (int i = 1; i <= n; ++i) {
if (type[i] || type[i + n]) {
continue;
}
if (!type[i] && !type[i] && fatin[i]) {
continue;
}
ans++;
}
printf ("%d
", ans);
for (int i = 1; i <= n; ++i) {
if (type[i] || type[i + n]) {
continue;
}
if (!type[i] && !type[i] && fatin[i]) {
continue;
}
printf ("%d", i);
ans--;
if (ans) {
printf (" ");
}
}
printf ("
");
return 0;
}
Conslusion
记住有向图找环用拓扑挺方便的。
学到了染色重建图的方法,有一点细节。真的是一点