博主的 BiBi 时间

我真的 \(\mathtt{biiiiiii}\)

我没有算空间复杂度就开始码,结果码了一个复杂度极高的算法,交上去就 \(\mathtt{MLE}\)\(\mathtt{QwQ}\).

Code (MLE)

我们只算大部头(即建边的复杂度)的复杂度。

\(500\times500\times 32\times 1\times 2=16000000=16000000\times 4/1024\text{ KB}=62500\text{ KB}\),然而你可以发现 \(\mathtt{HDU}\) 只开了三万多 \(\rm KB\).

炸了……

下面是代码,如果开大了嘤该能过。

\(\rm 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]\) 二进制分解一位一位地做就行了(比如异或就是当 \(b\) 这一位为 \(1\) 时,若 \(i\)\(1\)\(j\) 就必须选 \(0\))。

可以发现对于每个二进制位 \(x\),它的点都是可以独立跑的。我的空间复杂度高就高在我把每个二进制位的点都存了一遍,凭空乘了个 \(32\)……

Code

这道题的代码和 \(\text{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;
}
posted on 2020-06-19 09:49  Oxide  阅读(151)  评论(2编辑  收藏  举报