[比赛][ZJOI2011 day1]
2017-03-13 15:16
465 查看
[比赛][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[i−1][j][k],f[i][j−1][k],f[i−1][j−1][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))
注意要翻转两次,对每个面各做一次
[b]代码:[/b]
#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+1N−1∗(N−K+1)KN
[b]代码:[/b]
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个割了。
[b]代码:[/b]
#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; }
撒花~
相关文章推荐
- ZJOI2011 Day1 ( bzoj2227~2229 ) 题解
- [比赛][Zjoi2017 Day1]
- [ZJOI2011]基站选址
- [BZOJ2325][ZJOI2011][树链剖分][线段树]道馆之战
- BZOJ 2323: [ZJOI2011]细胞
- 【bzoj2325】【ZJOI2011】【道馆之战】【树链剖分】
- 【bzoj2324】[ZJOI2011]营救皮卡丘 最短路-Floyd+有上下界费用流
- BZOJ2324[ZJOI2011]营救皮卡丘
- P3329 [ZJOI2011]最小割
- bzoj 2229: [Zjoi2011]最小割 分治&网络流
- 【ZJOI2011】道馆之战
- 【BZOJ2229】[Zjoi2011]最小割【Gomory-Hu树】
- 2325: [ZJOI2011]道馆之战 (树链剖分+线段树)
- 【BZOJ2229】【ZJOI2011】最小割 {没有错,这道题的算法跟题帽是一样的!!!}
- [JZOJ2393]【ZJOI2011】营救皮卡丘
- ZJOI 2011 最小割 分治
- 【BZOJ2227】【ZJOI2011】看电影 [组合数][质因数分解]
- bzoj2229 [Zjoi2011]最小割(最小割树,分治)
- 【BZOJ 2324】 [ZJOI2011]营救皮卡丘
- bzoj 2324 [ZJOI2011]营救皮卡丘(floyd,费用流)