[比赛][ZJOI2011 day1]

3 篇文章 0 订阅

[比赛][ZJOI2011 day1]

pre():

只是用ZJOI2011的day1来考了一场省选模拟赛。。然而在这之前并没有做过。。

实际比赛:

T1

T1推了一下发现是一个Dp+单调栈?不过要分成三面做。。。于是打了半个小时调了一个小时,因为为了把三面中的某一面作为底面打了翻转操作,调了好久。。。

A掉了

T2

好神的数学题啊并不会,隐隐约约感觉是结论题。。

N,K<=10 感觉可以打暴力,打完发现复杂度是 NK 根本过不了。。。于是改成了打表。。但是打错了QAQ

爆0了

T3

好神的图论啊并不会,隐隐约约感觉是最小割(题目就是最小割啊)。。

N<=50 感觉可以打暴力,于是对每两对点跑了一遍最小割就过了样例(样例怎么一条边都没有),啊呀自己造了一组数据跑过了就不管了。

拿了暴力30分

总分130啊好数字

题解:

T1

f[i][j][k] 表示第 k 层以(i,j)为右下角的最大的正方形大小, g[i][j][k] 表示当前位置是否完好,那么:

f[i][j][k]=(Min(f[i1][j][k],f[i][j1][k],f[i1][j1][k])+1)g[i][j][k]

再枚举每个左下角 (i,j) ,不妨设 f[i][j][k] c[k] ,那么对于 c[k] 的一段区间,它的长宽肯定只能取这段区间里的最小值,所以用单调栈分别维护 c[k] 最小能向左右到 l[k] r[k] ,这样最大值就是:

ans=Max(c[k](r[k]l[k]+1))

注意要翻转两次,对每个面各做一次

代码:
#include <bits/stdc++.h>
using namespace std;
const int Maxn = 155;
int P, Q, R, g[Maxn][Maxn][Maxn], f[Maxn][Maxn][Maxn], ans, tmp[Maxn][Maxn][Maxn];
inline int Min(const int &a, const int &b) {
    return a < b ? a : b;
}
inline int Max(const int &a, const int &b) {
    return a > b ? a : b;
}
int c[Maxn], l[Maxn], r[Maxn], top, st[Maxn];
inline int calc(const int &n) {
    c[0] = c[n + 1] = -1;
    top = 0;
    for (int i = 1; i <= n; i++) {
        while (top && c[i] <= c[st[top]]) top--;
        l[i] = st[top] + 1; st[++top] = i;
    }
    top = 0; st[++top] = n + 1;
    for (int i = n; i; i--) {
        while (top && c[i] <= c[st[top]]) top--;
        r[i] = st[top] - 1; st[++top] = i;
    }
    for (int i = 1; i <= n; i++) ans = Max(ans, (r[i] - l[i] + 1) * c[i]);

}
inline void circle1(void) {
    for (int i = 1; i <= P; i++)
        for (int j = 1; j <= Q; j++)
            for (int k = 1; k <= R; k++) g[i][R - k + 1][j] = tmp[i][j][k];
    swap(Q, R);
}
inline void circle2(void) {
    swap(Q, R);
    for (int i = 1; i <= P; i++)
        for (int j = 1; j <= Q; j++)
            for (int k = 1; k <= R; k++) g[k][j][P - i + 1] = tmp[i][j][k];
    swap(P, R);
}
inline void solve(void) {
    for (int k = 1; k <= R; k++)
        for (int i = 1; i <= P; i++)
            for (int j = 1; j <= Q; j++) {
                if (g[i][j][k]) f[i][j][k] = Min(f[i - 1][j - 1][k], 
                Min(f[i - 1][j][k], f[i][j - 1][k])) + 1;
                else f[i][j][k] = 0;
            }
    for (int i = 1; i <= P; i++)
        for (int j = 1; j <= Q; j++) {
            memset(c, 0, sizeof c);
            for (int k = 1; k <= R; k++) 
                c[k] = f[i][j][k];
            calc(R);
        }

}
int main(void) {
    //freopen("monument.in", "r", stdin);
    //freopen("monument.out", "w", stdout);

    scanf("%d%d%d\n", &P, &Q, &R);
    for (int j = 1; j <= Q; j++)
        for (int i = 1; i <= P; i++) {
            for (int k = 1; k <= R; k++) tmp[i][j][k] = g[i][j][k] = (getchar() == 'N' ? 1 : 0);
            getchar();
        }
    solve(); circle1(); solve(); circle2(); solve(); 
    printf("%d\n", ans << 2);
    fclose(stdin), fclose(stdout);
    return 0;
}

T2

结论题吧,结论我不会证,答案是:

K+1N1(NK+1)KN

代码:
import math
import sys
import io
def gcd(a, b):
    if a < b:
                a, b = b, a

    while b != 0:
        temp = a % b
        a = b
        b = temp

    return a

t=int(input(''))
i = 1
while (i <= t):
    n, k = map(int,sys.stdin.readline().split())
    if n > k :
        print ("0 1")
    else :
        ans1 = math.pow((k + 1),(n - 1)) * (n - k + 1)
        ans2 = math.pow(k,n)
        g = gcd(ans1, ans2)
        ans1 = int(ans1 / g)
        ans2 = int(ans2 / g)
        print (ans1, ans2)

    i = i + 1

T3

fhq神犇题解:

首先,注意这样一个事实:如果(X,Y)是某个s1-t1最小割,(Z,W)是某个s2-t2最小割,那么X∩Z、X∩W、Y∩Z、Y∩W这四项不可能均非空。也就是说,最小割不可能相互跨立。

这个蕴含了,最多一共有N-1个不同的s-t最小割。只需把这些割找出来即可。

寻找的方法:首先,在V中任意找两个点a,b,求最大流,把V划分为割X-Y,之后对X、Y分别递归地进行划分。这样就能得到N-1个割了。

代码:
#include <bits/stdc++.h>
using namespace std;
const int Maxn = 200;
const int INF = 0x3f3f3f3f;
inline int Min(const int &a, const int &b) {
    return a < b ? a : b;
}
inline int Max(const int &a, const int &b) {
    return a > b ? a : b;
}
namespace IO {
    inline char get(void) {
        static char buf[1000000], *p1 = buf, *p2 = buf;
        if (p1 == p2) {
            p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin);
            if (p1 == p2) return EOF;
        }
        return *p1++;
    }
    inline void read(int &x) {
        x = 0; static char c; bool f = 0;
        for (; !(c >= '0' && c <= '9'); c = get()) if (c == '-') f = 1;
        for (; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = get()); if (f) x = -x;
    }
    inline void read(char &x) {
        x = get();
        while (!(x >= 'A' && x <= 'Z')) x = get();
    }
    inline void write(int x) {
        if (!x) return (void)puts("0");
        if (x < 0) putchar('-'), x = -x;
        static short s[12], t;
        while (x) s[++t] = x % 10, x /= 10;
        while (t) putchar('0' + s[t--]);
        putchar('\n');
    }
};
int head[Maxn], sub;
struct Edge {
    int to, nxt, v;
    Edge(void) {}
    Edge(const int &to, const int &nxt, const int &v) : to(to), nxt(nxt), v(v) {}
} edge[100005];
inline void add(int a, int b, int v) {
    edge[++sub] = Edge(b, head[a], v), head[a] = sub;
}
inline void restore(void) {
    for (int i = 2; i <= sub; i += 2)
        edge[i].v = edge[i ^ 1].v = (edge[i].v + edge[i ^ 1].v) >> 1;
}
int T, Q, n, m, ans[Maxn][Maxn], tmp[Maxn], a[Maxn], h[Maxn];
bool mark[Maxn];
inline bool bfs(int S, int T) {
    memset(h, -1, sizeof h);
    queue<int> qu;
    h[S] = 0; qu.push(S);
    while (!qu.empty()) {
        int u = qu.front(); qu.pop();
        for (int i = head[u], v; i; i = edge[i].nxt) {
            v = edge[i].to;
            if (h[v] == -1 && edge[i].v) h[v] = h[u] + 1, qu.push(v);
        }
    }
    return h[T] != -1;
}
inline int dfs(int T, int u, int flow) {
    if (u == T) return flow;
    int w, used = 0;
    for (int i = head[u], v; i; i = edge[i].nxt) {
        v = edge[i].to;
        if (h[v] != h[u] + 1) continue;
        w = dfs(T, v, Min(edge[i].v, flow - used));
        edge[i].v -= w; edge[i ^ 1].v += w;
        used += w;
        if (used == flow) return flow;
    }
    if (!used) h[u] = -1;
    return used;
}
inline void dfs(int x) {
    mark[x] = 1;
    for (int i = head[x], v; i; i = edge[i].nxt) {
        v = edge[i].to;
        if (edge[i].v && !mark[v]) dfs(v);
    }
}
inline void solve(int l, int r) {
    if (l == r) return ; restore();
    int S = a[l], T = a[r], t = 0;
    while (bfs(S, T)) t += dfs(T, S, INF);
    memset(mark, 0, sizeof mark);
    dfs(S);
    for (int i = 1; i <= n; i++)
        if (mark[i]) for (int j = 1; j <= n; j++)
        if (!mark[j]) ans[i][j] = ans[j][i] = Min(ans[i][j], t);
    int L = l, R = r;
    for (int i = l; i <= r; i++) {
        if (mark[a[i]]) tmp[L++] = a[i];
        else tmp[R--] = a[i];
    }
    for (int i = l; i <= r; i++) a[i] = tmp[i];
    solve(l, L - 1); solve(R + 1, r);
}
int main(void) {
    //freopen("in.txt", "r", stdin);
    IO::read(T);
    while (T--) {
        memset(head, 0, sizeof head);
        memset(ans, 0x3f, sizeof ans);
        sub = 1;
        IO::read(n), IO::read(m);
        for (int i = 1, u, v, w; i <= m; i++) {
            IO::read(u), IO::read(v), IO::read(w);
            add(u, v, w), add(v, u, w);
        }
        for (int i = 1; i <= n; i++) a[i] = i;
        solve(1, n);
        IO::read(Q);
        while (Q--) {
            int tans = 0, x;
            IO::read(x);

            for (int i = 1; i <= n; i++)
                for (int j = i + 1; j <= n; j++)
                    if (ans[i][j] <= x) tans++;
            IO::write(tans);
        }
        putchar('\n');
    }
    return 0;
}

撒花~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值