HNOI2013解题报告
来源:互联网 发布:钢笔日常书法知乎 编辑:程序博客网 时间:2024/06/05 09:50
HNOI2013解题报告
Author: Pengyihao
Day1 T1 比赛
思路
这是一道搜索的题目。
一个重要的优化就是,因为球队的分数排序后是不影响后面的答案的,所以判重的时候可以很方便。
然后还有就是
代码
#include <bits/stdc++.h>typedef long long LL;#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)template <typename Tp> void in(Tp &x) { char ch = getchar(), f = 1; x = 0; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar(); if (ch == '-') f = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= f;}template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}const int MAXN = 20, MOD = 1000000007;LL a[MAXN];std::map<LL, LL>mp;LL hash(int now){ LL res = now, tmp[MAXN]; FOR(i, 1, now) tmp[i] = a[i]; std::sort(tmp + 1, tmp + now + 1, std::less<int>()); FOR(i, 1, now) res += res * 28 + tmp[i]; return res;}LL DFS(int now, int n){ if (a[n] > 3 * (n - now)) return -1; LL res = 0; if (now == n) { if (n == 1) return 1; else { LL h = hash(n - 1); if (mp[h]) return mp[h]; return mp[h] = DFS(1, n - 1); } } if (a[n] >= 3) { LL tmp = 0; a[n] -= 3, tmp = DFS(now + 1, n); if (tmp != -1) (res += tmp) %= MOD; a[n] += 3; } if (a[n] && a[now]) { LL tmp = 0; a[n]--, a[now]--, tmp = DFS(now + 1, n); if (tmp != -1) (res += tmp) %= MOD; a[n]++, a[now]++; } if (a[now] >= 3) { LL tmp = 0; a[now] -= 3, tmp = DFS(now + 1, n); if (tmp != -1) (res += tmp) %= MOD; a[now] += 3; } return res ? res : -1;}int n;int main(){ freopen("match.in", "r", stdin); freopen("match.out", "w", stdout); in(n); FOR(i, 1, n) in(a[i]); std::sort(a + 1, a + n + 1, std::less<int>()); printf("%lld\n", DFS(1, n)); return 0;}
Day1 T2 消毒
思路
可以发现最优的话一定要是,选择的区域中的一维为
因为
把这一维看作高,然后枚举每一层选不选。
然后剩下的就转化成了二维问题。
这就是个典型的二分图最小点覆盖,网络流跑就可以了。
时间复杂度为
代码
#include <bits/stdc++.h>typedef long long LL;#define debug(...) fprintf(stderr, __VA_ARGS__)#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)template <typename Tp> void in(Tp &x) { char ch = getchar(), f = 1; x = 0; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar(); if (ch == '-') f = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= f;}template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}using std::vector;const int MAXN = 5002;bool chose[20];int a[4], ans;bool map[MAXN][MAXN];std::vector<std::vector<int> >g[MAXN];void init(){ ans = 0x3f3f3f3f; FOR(i, 1, 3) in(a[i]); FOR(i, 0, a[1] + 1) { g[i].resize(a[2] + 2); FOR(j, 0, a[2] + 1) g[i][j].resize(a[3] + 2); } FOR(i, 1, a[1]) { FOR(j, 1, a[2]) FOR(k, 1, a[3]) in(g[i][j][k]); }}const int ss = 0, tt = 5008, INF = 0x3f3f3f3f;using std::queue;queue<int>q;bool link[MAXN];int dis[5010], cur[5010];int cnt, head[5010], data[20010], flow[20010], nxt[20010];void add(int x, int y, int z){ nxt[cnt] = head[x]; data[cnt] = y; flow[cnt] = z; head[x] = cnt++; nxt[cnt] = head[y]; data[cnt] = x; flow[cnt] = 0; head[y] = cnt++;}int times, maxx = 1, alledge;struct Edge { int x, y; Edge(int a=0, int b=0): x(a), y(b) {}};std::vector<Edge>edge[20];bool bfs(){ dis[ss] = times; q.push(ss); while (!q.empty()) { int now = q.front(); q.pop(); for (int i = head[now]; i != -1; i = nxt[i]) { if (dis[data[i]] < times && flow[i]) { dis[data[i]] = dis[now] + 1; q.push(data[i]); chkmax(maxx, dis[now] + 1); } } } return dis[tt] >= times;}int dfs(int now, int fl){ if (now == tt) return fl; int flo; for (int i = head[now]; i != -1; i = nxt[i]) { if (flow[i] && dis[data[i]] == dis[now] + 1) { if (flo = dfs(data[i], Min(fl, flow[i]))) { flow[i] -= flo; flow[i ^ 1] += flo; return flo; } } } return 0;}void check(int minx){ int tmptot = 0; FOR(i, 1, minx) if (chose[i]) tmptot++; if (tmptot >= ans) return; cnt = 0; int tot = tmptot;// ***********************************************// make_Edge int Addition; if (minx == a[1]) Addition = a[2]; else if (minx == a[2]) Addition = a[1]; else Addition = a[1]; FOR(k, 1, minx) if (!chose[k]) { FOR(i, 0, edge[k].size() - 1) { int fr = edge[k][i].x, to = edge[k][i].y + Addition; if (!map[fr][to - Addition]) { add(fr, to, 1); if (!link[fr]) {link[fr] = true; add(ss, fr, 1);} if (!link[to]) {link[to] = true; add(to, tt, 1);} } } }// *********************************************** int fl = 0; times = maxx + 1; while (bfs()) { //memcpy(cur, head, sizeof head); int tmp; while (tmp = dfs(ss, INF)) fl += tmp; times = maxx + 1; } chkmin(ans, fl + tot); FOR(k, 1, minx) if (!chose[k]) FOR(i, 0, edge[k].size() - 1) { map[edge[k][i].x][edge[k][i].y] = false; link[edge[k][i].x] = link[edge[k][i].y + Addition] = false; head[edge[k][i].x] = head[edge[k][i].y + Addition] = -1; } head[ss] = head[tt] = -1;}void search(int now, int minx){ chose[now] = false; if (now == minx) check(minx); else search(now + 1, minx); chose[now] = true; if (now == minx) check(minx); else search(now + 1, minx); chose[now] = false;}void work(){ memset(head, -1, sizeof head); int minx = 5000; FOR(i, 1, 3) chkmin(minx, a[i]); alledge = 0; FOR(i, 1, minx) { edge[i].clear(); } if (minx == a[1]) { FOR(k, 1, a[1]) { FOR(i, 1, a[2]) FOR(j, 1, a[3]) if (g[k][i][j]) edge[k].push_back(Edge(i, j)); } } else if (minx == a[2]) { FOR(i, 1, a[1]) FOR(k, 1, a[2]) { FOR(j, 1, a[3]) if (g[i][k][j]) edge[k].push_back(Edge(i, j)); } } else { FOR(i, 1, a[1]) FOR(j, 1, a[2]) FOR(k, 1, a[3]) { if (g[i][j][k]) edge[k].push_back(Edge(i, j)); } } search(1, minx); printf("%d\n", ans); debug("%d\n", ans);}int main(){ freopen("clear.in", "r", stdin); freopen("clear.out", "w", stdout); int tcase; in(tcase); while (tcase--) { init(); work(); } return 0;}
Day1 T3 旅行
这是一道很难的题目。我看了题解也暂时无法解决此题,所以决定跳过它。
Day2 T1 数列
思路
考虑差分数列。
差分数列的可能数量为
于是答案就为
其中
所以最后答案为
代码
#include <bits/stdc++.h>typedef long long LL;#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)template <typename Tp> void in(Tp &x) { char ch = getchar(), f = 1; x = 0; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar(); if (ch == '-') f = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= f;}template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}LL ans = 0;LL n, k, m, p;LL power(LL x, LL y, LL p){ x %= p; LL ret = 1; while (y) { if (y & 1) ret = 1ll * ret * x % p; x = 1ll * x * x % p; y >>= 1; } return ret;}int main(){ freopen("seq.in", "r", stdin); freopen("seq.out", "w", stdout); in(n); in(k); in(m); in(p); n %= p; ans = 1ll * power(m, k - 1, p) * n % p; ans = ((ans - 1ll * (1ll * m * (m + 1) / 2) % p * (k - 1) % p * power(m, k - 2, p) % p) % p + p) % p; printf("%lld\n", ans); return 0;}
Day2 T2 游走
思路
我们可以贪心来做——求出每条边走过的期望次数,然后从大到小分配从
边的期望次数的求法是一个裸的高斯消元,这里就不再赘述。
代码
#include <bits/stdc++.h>const int MAXN = 510;bool f[MAXN][MAXN];int n, m, du[MAXN], all;long double matrix[MAXN][MAXN], times[MAXN], timess[MAXN * MAXN];template <typename Tp> void in(Tp &x) { char ch = getchar(); x = 0; while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();}void gauss() { for (int j = 1; j <= n; j++) { long double maxu = -1; int maxv = 0; for (int i = j; i <= n + 1; i++) if (maxu < fabs(matrix[i][j])) { maxu = fabs(matrix[i][j]); maxv = i; } for (int i = 1; i <= n + 1; i++) { long double t = matrix[j][i]; matrix[j][i] = matrix[maxv][i]; matrix[maxv][i] = t; } long double eps = matrix[j][j]; if (fabs(eps) < 1e-10) continue; for (int i = 1; i <= n + 1; i++) matrix[j][i] /= eps; for (int i = 1; i <= n + 1; i++) if (i != j) { long double epss = matrix[i][j]; if (fabs(epss) < 1e-10) continue; for (int k = 1; k <= n + 1; k++) matrix[i][k] -= matrix[j][k] * epss; } } for (int i = 1; i <= n; i++) times[i] = matrix[i][n + 1] / matrix[i][i]; for (int i = 1; i <= n; i++) for (int j = i + 1; j <= n; j++) if (f[i][j]) { if (j == n) timess[++all] = times[i] / du[i]; else timess[++all] = times[i] / du[i] + times[j] / du[j]; } std::sort(timess + 1, timess + all + 1); long double ans = 0; for (int i = 1; i <= all; i++) { ans += timess[i] * (all - i + 1); } printf("%.3Lf\n", ans);}int main() { freopen("walk.in", "r", stdin); freopen("walk.out", "w", stdout); in(n); in(m); for (int i = 1; i <= m; i++) { int u, v; in(u); in(v); f[u][v] = f[v][u] = true; if (u != n) du[u]++; if (v != n) du[v]++; } for (int i = 1; i <= n; i++) { for (int j = 1; j < n; j++) if (f[i][j]) matrix[i][j] = (long double)(1) / du[j]; matrix[i][i] = -1; if (i == 1) matrix[i][n + 1] = -1; } matrix[n + 1][n] = 1; matrix[n + 1][n + 1] = 1; gauss(); return 0;}
Day2 T3 切糕
思路
对于每一个位置,从所有层向上一层连边,容量为点权。
对于每一个位置,从第
对于每一个位置,从源点向第一层连边,容量为
对于每一个位置,从最高层向汇点连边,容量为
代码
#include <bits/stdc++.h>#define PLA(i, j, k) ((i) * 2500 + (j) * 50 + (k))typedef long long LL;#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)template <typename Tp> void in(Tp &x) { char ch = getchar(), f = 1; x = 0; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar(); if (ch == '-') f = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= f;}template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}int p, qs, r, d;int height[50][50][50];int cnt, dis[200010], head[200010], data[200010 << 1], flow[200010 << 1], cur[200010], nxt[200010 << 1];using std::queue; queue<int>q;const int ss = 0, tt = 200009, INF = 0x3f3f3f3f;bool bfs(){ memset(dis, -1, sizeof dis); dis[ss] = 0; q.push(ss); while (!q.empty()) { int now = q.front(); q.pop(); for (int i = head[now]; i != -1; i = nxt[i]) { if (dis[data[i]] == -1 && flow[i]) { dis[data[i]] = dis[now] + 1; q.push(data[i]); } } } return dis[tt] != -1;}int dfs(int now, int fl){ if (now == tt) return fl; int flo; for (int &i = cur[now]; i != -1; i = nxt[i]) { if (flow[i] && dis[data[i]] == dis[now] + 1) { if (flo = dfs(data[i], Min(fl, flow[i]))) { flow[i] -= flo; flow[i ^ 1] += flo; return flo; } } } return 0;}void add(int x, int y, int z){ nxt[cnt] = head[x]; data[cnt] = y; flow[cnt] = z; head[x] = cnt++; nxt[cnt] = head[y]; data[cnt] = x; flow[cnt] = 0; head[y] = cnt++;}int main(){ freopen("cake.in", "r", stdin); freopen("cake.out", "w", stdout); memset(head, -1, sizeof head); in(p); in(qs); in(r); in(d); FOR(i, 1, r) { FOR(j, 1, p) FOR(k, 1, qs) in(height[i][j][k]); } FOR(i, 1, p) FOR(j, 1, qs) { add(ss, PLA(i, j, 1), INF); FOR(k, 1, r) { add(PLA(i, j, k), PLA(i, j, k + 1), height[k][i][j]); } add(PLA(i, j, r + 1), tt, INF); } FOR(i, 1, p) FOR(j, 1, qs) { FOR(k, d + 1, r + 1) { if (i != p) add(PLA(i, j, k), PLA(i + 1, j, k - d), INF); if (i != 1) add(PLA(i, j, k), PLA(i - 1, j, k - d), INF); if (j != qs) add(PLA(i, j, k), PLA(i, j + 1, k - d), INF); if (j != 1) add(PLA(i, j, k), PLA(i, j - 1, k - d), INF); } } int fl = 0; while (bfs()) { memcpy(cur, head, sizeof head); int tmp; while (tmp = dfs(ss, INF)) fl += tmp; } printf("%d\n", fl); return 0;}
阅读全文
2 0
- HNOI2013解题报告
- hnoi2013
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- Antiprime解题报告
- expr解题报告
- 华容道解题报告
- tju解题报告
- zju1062/pku1095解题报告
- UsacoGate解题报告 --- 序曲
- ZJU 2060 解题报告
- ZJU 1331 解题报告
- ZJU 1115 解题报告
- codeforces235E
- c++实验6-矩阵求和
- matlab产生扫频余弦信号 chirp用法
- c/c++ 函数指针的用法
- 作用域
- HNOI2013解题报告
- “System.Configuration”中不存在类型或命名空间名称“ConfigurationManager”
- ios mysql 学习1 首先建立自己的主页及数据
- 『ORACLE』 内置约束(11g)
- python的安装和代码保存
- poj3233 等比矩阵二分求和
- 辗转相除法求最大公约数
- HNOI2011解题报告
- 实习第五天 工作总结