---
tags: 题解,算法
---
# 部分题解:[从入门到头秃周末休闲赛73 (F ~ I)](https://vjudge.net/contest/444713)
## F 秤 **
对w集合进行DFS,找出所有能称出来的质量集合,然后对每个不能称出来的ai求一个需要添加的w质量的集合,最后求它们的交集的最小值。
### 参考代码(C++11)
```cpp=
#include <iostream>
#include <set>
#include <vector>
using namespace std;
void dfs(int w[], int len, int sum, set<int>& s) {
if (len == 0) { s.insert(sum); return; }
dfs(w, len - 1, sum, s);
dfs(w, len - 1, sum + w[len - 1], s);
dfs(w, len - 1, sum - w[len - 1], s);
}
int solve(int n, int a[], int m, int w[]) {
set<int> s, r;
dfs(w, m, 0, s);
for (int i = 0; i < n; ++i)
if (s.count(a[i])) swap(a[i--], a[--n]);
if (n == 0) return 0;
for (auto& it : s)
r.insert(abs(it - a[0]));
for (int i = 1; i < n; ++i) {
set<int> t;
for (auto& it : s) {
int v = abs(it - a[i]);
if (r.count(v))
t.insert(v);
}
r = move(t);
}
if (r.empty()) return -1;
return *r.begin();
}
int main() {
int n, m;
int a[200], w[20];
while (cin >> n >> m && n + m > 0) {
for (int i = 0; i < n; ++i) cin >> a[i];
for (int i = 0; i < m; ++i) cin >> w[i];
cout << solve(n, a, m, w) << endl;
}
return 0;
}
```
以上方法不是最优,换个迭代方式可以节省2/3时间。
## G 最大矩形 ***
### 方法1
设`'#'`表示1,`'.'`表示0的话,通过观察你会发现,这个最大矩形里,假设第一行是v0,那么接下来的几行,要么是v0,要么是~v0,同样,按列算也是一样。那么,我们穷举这个最大矩形的下边界,然后以此计算相邻的两列,最高有多高满足它们是完全相等或完全相反,这样就得到一个大小为w-1的高度数组,那就变成典型的单调栈题。本题也类似01矩阵里面找最大的全0矩阵的题目。
### 方法2
通过方法1的规律做出推论,把原矩阵里,共`(h-1)*(w-1)`个2x2小矩阵,我们就来生成这个新的`(h-1)*(w-1)`矩阵,如果这个小矩阵里面1的个数是奇数,那用1表示,否则用0表示,那么原题就变成在新矩阵里找最大的全0矩阵,套模板即可。
## H 困兽斗 ***
求出所有交点,并根据线段相连成若干个平面图,这些图之间没有交点。然后,对于每个平面图,扫描出它的包围多边形(度为1的点可以在生成平面图时删去),最后就转化成判断原点在不在多边形内的问题,解法是计算这个多边形有多少次穿越x正半轴,如果是奇数次,那么原点在多边形内,否则就在多边形外。如果原点在任一多边形内,输出yes,否则输出no就可以了。
## I 树上游戏 ****
本题网上到处都是题解,直接搜索或看[这个](https://blog.csdn.net/baidu_36797646/article/details/88571722)