博主的 BiBi 时间
我真的 \(\mathtt{biiiiiii}\)。
我没有算空间复杂度就开始码,结果码了一个复杂度极高的算法,交上去就 \(\mathtt{MLE}\) 了 \(\mathtt{QwQ}\)。
Code
我们只算大部头(即建边的复杂度)的复杂度。
\(500*500*32*1*2=16000000=16000000*4/1024KB=62500KB\),然而你可以发现 \(\mathtt{HDU}\) 只开了三万多 \(KB\)。
炸了。。。
下面是代码,如果开大了嘤该能过。
Update:好吧其实开大了也过不了,题目还有一个坑:输入的 \(b\) 数组从 \(0\) 开始!!!
#include <cstdio>
#include <cstring>
const int N = 32000, M = 3e6 + 500;
int a[505][505], n, head[N], Head[N], be[N], scc[N], tot, cnt, to[M], nxt[M];
bool vis[N];
int read() {
int x = 0, f = 1; char s;
while((s = getchar()) > '9' || s < '0') if(s == '-') f = -1;
while(s >= '0' && s <= '9') x = (x << 1) + (x << 3) + (s ^ 48), s = getchar();
return x * f;
}
void addEdge(const int u, const int v) {
to[++ cnt] = v, nxt[cnt] = head[u], head[u] = cnt;
to[++ cnt] = u, nxt[cnt] = Head[v], Head[v] = cnt;
}
void dfs1(const int u) {
vis[u] = 1;
for(int i = head[u]; i; i = nxt[i])
if(! vis[to[i]]) dfs1(to[i]);
scc[++ tot] = u;
}
void dfs2(const int u) {
vis[u] = 1; be[u] = tot;
for(int i = Head[u]; i; i = nxt[i])
if(! vis[to[i]]) dfs2(to[i]);
}
void Kosaraju() {
memset(vis, 0, sizeof vis); tot = 0;
for(int i = 0; i < 64 * n; ++ i) if(! vis[i]) dfs1(i);
memset(vis, 0, sizeof vis); tot = 0;
for(int i = 64 * n - 1; ~i; -- i)
if(! vis[scc[i]]) ++ tot, dfs2(scc[i]);
}
int main() {
int len, x[35], p; bool flag;
while(~ scanf("%d", &n)) {
memset(head, 0, sizeof head); memset(Head, 0, sizeof Head); cnt = 0; flag = 0;
for(int i = 1; i <= n; ++ i)
for(int j = 1; j <= n; ++ j)
a[i][j] = read();
for(int i = 1; i <= n; ++ i) {
if(a[i][i]) {puts("NO"); flag = 1; break;}
for(int j = 1; j <= n; ++ j)
if(a[i][j] != a[j][i]) {puts("NO"); flag = 1; break;}
}
if(flag) continue;
for(int i = 1; i <= n; ++ i) {
for(int j = i + 1; j <= n; ++ j) {
len = 0;
while(a[i][j]) x[++ len] = (a[i][j] & 1), a[i][j] >>= 1;
if((i & 1) && (j & 1)) {
for(int k = 1; k <= (len << 1); k += 2)
if(x[k] & 1) addEdge((i - 1) * 64 + k - 1, (j - 1) * 64 + k), addEdge((j - 1) * 64 + k - 1, (i - 1) * 64 + k);
else addEdge((i - 1) * 64 + k, (i - 1) * 64 + k - 1), addEdge((j - 1) * 64 + k, (j - 1) * 64 + k - 1);
}
else if(i % 2 == 0 && j % 2 == 0) {
for(int k = 1; k <= (len << 1); k += 2)
if(x[k] & 1) addEdge((i - 1) * 64 + k - 1, (i - 1) * 64 + k), addEdge((j - 1) * 64 + k - 1, (j - 1) * 64 + k);
else addEdge((i - 1) * 64 + k, (j - 1) * 64 + k - 1), addEdge((j - 1) * 64 + k, (i - 1) * 64 + k - 1);
}
else {
for(int k = 1; k <= (len << 1); k += 2) {
if(x[k] & 1) addEdge((i - 1) * 64 + k - 1, (j - 1) * 64 + k), addEdge((i - 1) * 64 + k, (j - 1) * 64 + k - 1),
addEdge((j - 1) * 64 + k - 1, (i - 1) * 64 + k), addEdge((j - 1) * 64 + k, (i - 1) * 64 + k - 1);
else addEdge((i - 1) * 64 + k - 1, (j - 1) * 64 + k - 1), addEdge((i - 1) * 64 + k, (j - 1) * 64 + k),
addEdge((j - 1) * 64 + k - 1, (i - 1) * 64 + k - 1), addEdge((j - 1) * 64 + k, (i - 1) * 64 + k);
}
}
}
}
Kosaraju();
for(int i = 0; i < n; ++ i)
for(int j = 1; j <= 64; j += 2)
if(be[i + j - 1] == be[i + j] && be[i + j]) {flag = 1; break;}
puts(flag ? "NO" : "YES");
}
return 0;
}
Solution
其实想出正解有点骄傲(其实没什么骄傲的,我只是太蒻了)。
我们可以枚举 \(i,j\),将 \(b[i][j]\) 二进制分解一位一位地做就行了(比如异或就是 \(i\) 选 \(1\),\(j\) 就必须选 \(0\))。
可以发现对于每个二进制位 \(x\),它的点都是可以独立跑的。我的空间复杂度高就高在我把每个二进制位的点都存了一遍,凭空乘了个 \(32\)。。。
Code
这道题的代码和 HDU - 3622 Bomb Game 是一样的坑,然后我又掉进去了。。。
#include <cstdio>
#include <cstring>
const int N = 32000, M = 1e6 + 500;
int a[505][505], n, head[N], Head[N], be[N], scc[N], tot, cnt, to[M], nxt[M];
bool vis[N];
int read() {
int x = 0, f = 1; char s;
while((s = getchar()) > '9' || s < '0') if(s == '-') f = -1;
while(s >= '0' && s <= '9') x = (x << 1) + (x << 3) + (s ^ 48), s = getchar();
return x * f;
}
void addEdge(const int u, const int v) {
to[++ cnt] = v, nxt[cnt] = head[u], head[u] = cnt;
to[++ cnt] = u, nxt[cnt] = Head[v], Head[v] = cnt;
}
void dfs1(const int u) {
vis[u] = 1;
for(int i = head[u]; i; i = nxt[i])
if(! vis[to[i]]) dfs1(to[i]);
scc[++ tot] = u;
}
void dfs2(const int u) {
vis[u] = 1; be[u] = tot;
for(int i = Head[u]; i; i = nxt[i])
if(! vis[to[i]]) dfs2(to[i]);
}
void Kosaraju() {
memset(vis, 0, sizeof vis); tot = 0;
for(int i = 0; i < (n << 1); ++ i) if(! vis[i]) dfs1(i);
memset(vis, 0, sizeof vis); tot = 0;
for(int i = (n << 1) - 1; ~i; -- i)
if(! vis[scc[i]]) ++ tot, dfs2(scc[i]);
}
int main() {
bool flag;
while(~ scanf("%d", &n)) {
flag = 0;
for(int i = 1; i <= n; ++ i)
for(int j = 1; j <= n; ++ j)
a[i][j] = read();
for(int i = 1; i <= n; ++ i) {
if(a[i][i]) {puts("NO"); flag = 1; break;}
for(int j = 1; j <= n; ++ j)
if(a[i][j] != a[j][i]) {puts("NO"); flag = 1; break;}
}
if(flag) continue;
for(int k = 0; k < 31; ++ k) {
memset(head, 0, sizeof head); memset(Head, 0, sizeof Head); cnt = 0;
for(int i = 1; i <= n; ++ i) {
for(int j = i + 1; j <= n; ++ j) {
int bit = ((1 << k) & a[i][j]);
if((i - 1 & 1) && (j - 1 & 1)) {
if(bit) addEdge(i - 1, j - 1 + n), addEdge(j - 1, i - 1 + n);
else addEdge(i - 1 + n, i - 1), addEdge(j - 1 + n, j - 1);
}
else if((i - 1) % 2 == 0 && (j - 1) % 2 == 0) {
if(bit) addEdge(i - 1, i - 1 + n), addEdge(j - 1, j - 1 + n);
else addEdge(i - 1 + n, j - 1), addEdge(j - 1 + n, i - 1);
}
else {
if(bit) addEdge(i - 1, j - 1 + n), addEdge(i - 1 + n, j - 1),
addEdge(j - 1, i - 1 + n), addEdge(j - 1 + n, i - 1);
else addEdge(i - 1, j - 1), addEdge(i - 1 + n, j - 1 + n),
addEdge(j - 1, i - 1), addEdge(j - 1 + n, i - 1 + n);
}
}
}
if(! cnt) break;
Kosaraju();
for(int i = 0; i < n; ++ i) if(be[i] == be[i + n]) {flag = 1; break;}
if(flag) break;
}
puts(flag ? "NO" : "YES");
}
return 0;
}