开始听日术 | 2023.6.26做题记录
开始听日术 | 2023.6.26做题记录
CF1820D. The Butcher
是补题。
因为不会旋转,所以每个矩形长/宽在切割的过程中一定是不升的,每次找到在剩下的矩形中长/宽最大的接上去即可。答案最多有俩。
因为没注意到面积不变没写出来……贺了题解
CF1735E. House Planning
还是补题,不会。
数据范围是 \(\mathcal O(n^2)\) 的样子,可以有一点暴力点的做法!
考虑暴力枚举一个 \(d_{2,k}\) 和 \(d_{1,1}\) 是同一个建筑的贡献,其中假设 \(p_1=0\)
我们发现一栋建筑和 \(p_1\) 与 \(p_2\) 的位置关系是有两种可能的,在中间和在两侧
假设两个距离分别是 \(d_1,d_2\),我们钦定这个点是原点,可以算出两种情况下 \(p_1,p_2\) 的位置,然后线性check
具体的说,不妨钦定 \(p_1\) 是 \(0-d_1\),\(p_2\) 是 \(0-d_2\),那么如果这是一个合法的方案,则对于任何一个 \(p_1\) 得到的 \(d_1\),要么有一个 \(d_2\) 满足 \(d_1+d_2=p_2-p_1\),要么满足 \(|d_1-d_2|=p_2-p_1\)
然后如果找到一个 \(d_2\) 就暴力删就行了
Upd: 假的
Upd2:从大到小排序就是真的了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
int n;
std::vector<int> d[2];
std::vector<int> a;
bool check(int p, int p1, int p2) {
std::multiset<int> st;
for (int i = 0; i < n; i++)
if (i != p)
st.insert(d[1][i]);
for (int i = 1; i < n; i++) {
int pos = p1 + d[0][i];
if(st.find(abs(pos-p2)) != st.end()) {
a[i] = pos;
st.erase(st.find(abs(pos-p2)));
} else {
pos = p1 - d[0][i];
if(st.find(abs(pos-p2)) != st.end()) {
a[i] = pos;
st.erase(st.find(abs(pos-p2)));
} else {
return false;
}
}
}
return true;
}
bool cmp(int a, int b) {
return a > b;
}
void solve() {
std::cin >> n;
d[0].resize(n), d[1].resize(n);
a.resize(n);
a[0] = 0;
for (int i = 0; i < n; i++)
std::cin >> d[0][i];
for (int i = 0; i < n; i++)
std::cin >> d[1][i];
bool solved = false;
std::multiset<int> st;
std::sort(d[0].begin(), d[0].end(), cmp);
std::sort(d[1].begin(), d[1].end(), cmp);
int p1, p2;
for (int p = 0; p < n; p++) {
p1 = 0 - d[0][0], p2 = 0 + d[1][p];
solved = check(p, p1, p2);
if(solved) break;
p1 = 0 - d[0][0], p2 = 0 - d[1][p];
solved = check(p, p1, p2);
if(solved) break;
p1 = 0 + d[0][0], p2 = 0 + d[1][p];
solved = check(p, p1, p2);
if(solved) break;
p1 = 0 + d[0][0], p2 = 0 - d[1][p];
solved = check(p, p1, p2);
if(solved) break;
}
if(!solved)
std::cout << "NO\n";
else {
std::cout << "YES\n";
int mina = 1e9;
for(int i : a)
mina = std::min(mina, i);
mina = std::min(mina, std::min(p1, p2));
for(int &i : a)
i -= mina;
for(int i : a)
std::cout << i << ' ';
std::cout << '\n';
std::cout << p1 - mina << ' ' << p2 - mina << '\n';
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
int T;
std::cin >> T;
while (T--) {
solve();
}
return 0;
}
CF1841C. Ranom Numbers
考虑DP,用 \(f_{i,j,k}\) 表示第 \(i\) 位,\(j\in \{0,1\}\) 表示已经变了或还没有变,\(k\) 表示最大的字母
然后就做完了。