上午
考试 ### 第一题
一句话题意:给你几堆火,给你几个罐子,这几个罐子分别对火可能会产生不同的影响,每次使用罐子的时候都必须对全部的火进行操作,\(1\)表示浇灭,\(0\)表示 无影响,\(-1\) 表示点燃
问最少用几次罐子可以把火浇灭,否则输出“-1”
一眼搜索
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| #include <bits/stdc++.h> #define LL long long #define debug using namespace std;
const int N = 1e3+250;
queue<int>q; map<LL, int> vis, dis; int n, m; int zuikaishideyangzi, moweideyangzi; int a[250][250];
inline void shuruyijichushihua() { cin >> n >> m; for (int i = 1; i <= n; ++ i) zuikaishideyangzi = zuikaishideyangzi * 10 + 1; dis[zuikaishideyangzi] = 0; vis[zuikaishideyangzi] = 1; for (int i = 1; i <= m; ++ i) { for (int j = 1; j <= n; ++ j) { cin >> a[i][j]; } } q.push(zuikaishideyangzi); return; }
inline void jiejuewenti() { while (q.size()) { int now = q.front(); q.pop(); if (now == moweideyangzi) return; int tmp = n, shu[66], yuan[66]; int xianzaideyangzi = now; while (tmp != 0) { yuan[tmp] = shu[tmp] = xianzaideyangzi%10; -- tmp; xianzaideyangzi /= 10; } for (int i = 1; i <= m; ++ i) { for (int j = 1; j <= n; ++ j) { if (a[i][j] == 1) shu[j] = 0; if (a[i][j] == -1) shu[j] = 1; } LL houlainayiwei = 0; for (int j = 1; j <= n; ++ j) { houlainayiwei = houlainayiwei*10 + shu[j]; shu[j] = yuan[j]; } if (!vis.count(houlainayiwei)) { vis[houlainayiwei] = 1; dis[houlainayiwei] = dis[now] + 1; q.push(houlainayiwei); } } } }
inline void shuchudaan() { if (vis[moweideyangzi]) cout << dis[moweideyangzi]; else puts ("-1"); return; }
inline int thestars() { shuruyijichushihua(); jiejuewenti(); shuchudaan(); return 0; }
int youngore = thestars();
signed main() {;}
|
第二题
photo
一眼贪心,我们观察样例以及样例解释
Code
3 1
2 2
4 3
样例解释:
如果没人躺过来,需要27的面积。
我们只要让第1个人躺过来,就只需要21的面积!
开始揣测,为什么一定要让第一个人的\(w\)与\(h\)翻转?为什么不是别人?如果别人翻转会是什么样子的?
画图发现
在第一个人的\(w\)与\(h\)翻转前后,他们的\(maxh\)一直都是3,只是他们的\(sumw\)变小了,所以整体的体积变小了
在经过一段时间的臆想,我决定给他们按某种方式的排序,或许会好做一些
考虑:按\(h\)的高度大小排序?显然不合适,没有考虑全体,缺点太多
考虑:按\(w\)的大小排序?显然要被否定
于是继续臆想,最终决定按一个数的\(h\)与\(w\)的差值来从大到小来排序(他们的绝对值)
于是原来的样例变成这样:
Code
3 1(3-1=2)
4 3(4-3=1)
2 2(2-2=0)
我们肯定优先是对那些\(h\)与\(w\)差值大的组合进行翻转,因为只有这样才有可能对答案产生有效或者更大的贡献
这时候再来考虑:
\(h\)与\(w\)大小的关系
- \(w > h\)
- \(w < h\)
- \(w = h\)
显然对于第三种情况我们无论是否调换\(w\)\(h\)都是无影响的
分情况讨论第一种与第二种情况:
当\(w>h\)的时候,考虑\(w\)是否影响\(maxh\)
1.\(w <maxh\),此时交换\(w\)与\(h\)显然是优的,因为我们在\(maxh\)没有变动的情况下,是的\(sumw\)尽量的小
2.\(w>maxh\),这时候直接交换不一定是优的,因此我们需要计算一下交换之后的面积
如果\(面积_{当前算出来的}
>面积_{以前算出来的}\) 显然不优,我们不去交换\(w\)与\(h\),反之则交换,并注意更新\(maxh\)与一些数组
当\(w < h\)的时候,考虑\(maxh\)与\(h\)的关系
1.\(h\neq
maxh\),显然,我交换之后不影响你\(h\)的最大值,并且交换之后,我\(sumw\)还变大了,面积也会变大,显然不优,我们不去交换
2.\(h = maxh\),还要继续分析:
整体序列是否只有这么一个\(maxh\),那我们需要计算交换之后的面积,然后……(上文提过,此处省略)
如果不止一个\(maxh\),那我们交换之后显然吃亏,因为我们交换之后的\(h\)没有影响到\(maxh\)并且我的\(sumw\)也变大了
算法整体就结束了,不过仍然有一个细节要注意,因为题目规定,要求不超过\(\dfrac n
2\)的修改个数,所以每一次交换之后,都需要累加计数器,如果发现计数器大于\(\dfrac n 2\)就退出
底下是90分代码,还需要经过我再D一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <queue> #include <vector> #include <cmath>
using namespace std;
const int N = 1e5+66;
struct node {int h, w, cha;}a[N];
inline int cmp(node x, node y) {return x.cha > y.cha;}
int n, m, sum; int sumw[N], maxh = -N;
int main () { scanf ("%d", &n); m = n>>1; int dodododo = 0; for (int i = 1; i <= n; ++ i) { scanf ("%d%d", &a[i].w, &a[i].h); a[i].cha = abs(a[i].w-a[i].h); dodododo += a[i].w; maxh = (maxh>a[i].h)?maxh:a[i].h; } sum = dodododo*maxh; #ifdef debug cout << "dodododo-->" << dodododo << ' ' << "maxh-->" << maxh << '\n'; cout << "sum-->" << sum << '\n'; #endif sort (a+1, a+n+1, cmp); #ifdef debug for (int i = 1; i <= n; ++ i) cout << a[i].w << ' ' << a[i].h << '\n'; #endif for (int i = 1; i <= n; ++ i) sumw[i] = sumw[i - 1] + a[i].w; for (int i = 1; i <= n; ++ i) { if (m == 0) break; if (a[i].w > a[i].h) { if (a[i].w <= maxh) { sum = maxh*(sumw[i - 1]+a[i].h+sumw[n]-sumw[i]); swap(a[i].w, a[i].h); for (int j = i; j <= n; ++ j) sumw[j] = sumw[j - 1] + a[j].w; -- m; } else { int ans = a[i].w*(sumw[i-1]+a[i].h+sumw[n]-sumw[i]); if (ans < sum) { sum = ans; for (int j = i; j <= n; ++ j) maxh = a[i].w; -- m; } else continue; } } if (a[i].w == a[i].h) {continue;} if (a[i].w < a[i].h) { if (maxh != a[i].h) {continue;} if (maxh == a[i].h) { int flag = 0; for (int j = 1; j <= n; ++ j) if (a[j].h == maxh) ++ flag; flag -= 1; if (flag) {continue;} else { int one = -N; for (int j = 1; j < i; ++ j) one =(one>a[j].h)?one:a[j].h; for (int j = i+1; j <= n; ++ j) one =(one>a[j].h)?one:a[j].h; one = (one>a[i].w)?one:a[i].w; int ans = one*(sumw[i-1]+a[i].h+sumw[n]-sumw[i]); if (ans < sum) { sum = ans; maxh = one; swap(a[i].w, a[i].h); for (int j = i; j <= n; ++ j)sumw[j]=sumw[j - 1] + a[i].w; } else {continue;} } } } } cout << sum; return 0; }
|
第三题
eat
一眼枚举
关于吃东西这道题,我们首先来分析一下题意
给你\(ABCD\)四堆数,告诉每堆数里面你必须选一个,再给你一个判定器n,问你有多少种方案选数?
最暴力的做法,四重for,可以拿到三十分
然后考虑优化,最简单的优化是知道前三个数,然后利用判定器减去前三数的和就可以得到第四个数
在这个题中,我们如果知道了\(A+B\)的和,就可以很容易的推出\(C+D\)的具体范围,
具体做法:枚举出\(A+B\)的所有组合,再枚举\(C+D\)的所有组合,
我们定义\(C1,C2\)数组
其中\(C1[i]=x\)就表示\(A+B\)所能凑出来的和的第\(i\)种方案,其价值为\(x\),同理
\(C2[i] = x\)表示\(C+D\)所能凑出来的和的第\(i\)种方案,其价值为\(x\)
在\(C2\)数组中找到能与\(C1\)数组匹配的数的下标,然后就可以累加答案
更具体的分析在代码中
下面是自己的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #include <bits/stdc++.h> #define int long long #define LL long long #define debug using namespace std;
const int N = 1e8+66, M = 5e3+66, P = 2e7+2;
int n, cnt1, cnt2, maxn, res; int A, B, C, D; int a[M], b[M], c[M], d[M]; int c1[P], c2[N], f[N]; inline int thestars() { cin >> n >> A >> B >> C >> D; for (int i = 1; i <= A; ++ i) cin >> a[i]; for (int i = 1; i <= B; ++ i) cin >> b[i]; for (int i = 1; i <= C; ++ i) cin >> c[i]; for (int i = 1; i <= D; ++ i) cin >> d[i]; for (int i = 1; i <= A; ++ i) { for (int j = 1; j <= B; ++ j) { if (a[i] + b[j] <= n) { ++ f[a[i] + b[j]]; maxn = max (maxn, a[i] + b[j]); } } } for (int i = 0; i <= maxn; ++ i) { while (f[i]) { -- f[i]; c1[++ cnt1] = i; } } maxn = 0; for (int i = 1; i <= C; ++ i) { for (int j = 1; j <= D; ++ j) { if (c[i] + d[j] <= n) { ++ f[c[i] + d[j]]; maxn = max (maxn, c[i] + d[j]); } } } for (int i = 0; i <= maxn; ++ i) { while (f[i]) { -- f[i]; c2[++ cnt2] = i; } } int cur; for (cur = cnt2; cur >= 1; -- cur) if (c1[1] + c2[cur] <= n) break; for (int i = 1; i <= cnt1; ++ i) { res += cur;
while (cur && c1[i + 1] + c2[cur] > n) -- cur;
} cout << res << '\n'; return 0; }
int youngore = thestars();
signed main() {;}
|