ARC172 补
A Chocolate
给你一个 \(h\times w\) 的大矩形,问它能否被割成 \(n\) 个矩形,使得第 \(i\) 的边长为 \(2^{a_i}\)。
Solution
考虑怎么分割,注意到直接按 \(a\) 分可能不好处理也无法确定分割方案方式,注意到边长全是 \(2\) 的次幂,所以可以按指数割,这样大矩形一定不会影响小矩形分割,同时可以不用存储分割方案,既然大矩形可以塞下不如直接转化为小矩形便于计算。
\(\\\)
Code
// STOOOOOOOOOOOOOOOOOOOOOOOOO hzt CCCCCCCCCCCCCCCCCCCCCCCORZ
#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>
using namespace std;
using LL = long long;
using PII = pair<int, int>;
int c[26];
int main() {
cin.tie(0)->sync_with_stdio(0);
int h, w, n, a;
cin >> h >> w >> n;
for (int i = 1, x; i <= n; i++) {
cin >> x;
c[x]++;
}
LL tmp = 0;
for (int i = 25; i >= 0; i--) {
LL v = 1 << i;
if ((h / v) * (w / v) < tmp + c[i]) {
cout << "No\n";
return 0;
}
tmp += c[i];
tmp *= 4;
}
cout << "Yes\n";
return 0;
}
B AtCoder Language
问有多少个长度为 \(n\) 值域为 \([1, l]\) 的序列满足所有长度为 \(k\) 的子序列各不相同。
Solution
显然两相同数至少隔着 \(n-k\) 个数,不然必然都可以放在一个子序列的同一位置,就会产生相同子序列。然后直接算每一位有几种可能数即可。
\(\\\)
Code
#include <bits/stdc++.h>
#include <atcoder/modint>
using namespace std;
using namespace atcoder;
#define all(v) (v).begin(), (v).end()
using ll = long long;
using ld = long double;
using pint = pair<int, int>;
using pll = pair<ll, ll>;
using mint = modint998244353;
int main() {
int N, K, L;
cin >> N >> K >> L;
mint ans = 1;
for (int i = 0; i < N; i++) {
if (L - i + max(0, i - (N - K)) <= 0) {
cout << 0 << endl;
return 0;
}
ans *= L - i + max(0, i - (N - K));
}
cout << ans.val() << endl;
}
C Election
给定一个长度为 \(n\) 值域 \([-1,1]\) 的差分序列,问有多少种序列满足把第一个数插入到后面任意位置后的差分序列为给定序列。
Solution
直接模拟。
\(\\\)
Code
// STOOOOOOOOOOOOOOOOOOOOOOOOO hzt CCCCCCCCCCCCCCCCCCCCCCCORZ
#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>
using namespace std;
using LL = long long;
using PII = pair<int, int>;
int n, s1, s2;
string s;
int main() {
cin.tie(0)->sync_with_stdio(0);
cin >> n >> s;
vector<int> a(n);
for (int i = 1; i < n; i++) {
s[i] == 'A' ? s1++ : s2++;
a[i] = 2 * (s1 < s2) + (s1 > s2);
}
int ans = 0;
for (int i = n - 1; i >= 1; i--) {
s[i] == 'A' ? s1-- : s2--;
s[0] == 'A' ? s1++ : s2++;
int c = 2 * (s1 < s2) + (s1 > s2);
ans += c != a[i];
s[0] == 'A' ? s1-- : s2--;
}
cout << ans + 1 << '\n';
return 0;
}
D Distance Ranking
在 \(n\) 维空间中有 \(n\) 个点,给出两两之间欧几里得距离的排名,求构造一组点满足条件。
Solution
先让所有点的欧几里得距离相同,然后加以偏扰,来得到想要的排名。不难想到下列构造方案:
考虑点 \(i\) 和 \(j\) 的欧几里得距离,有点复杂,不如先看看例子中的 \(1\) 和 \(2\)。
有 \(d_{1, 2} = \sqrt{1 + (1-\epsilon_{1,2})^2+(\epsilon_{1,3}-\epsilon{2,3})^2+(\epsilon_{1,4}-\epsilon{2,4})^2}\).
拆开来看,由于 \(\epsilon\) 已极小,若其次数为二更是影响几乎不存在,可以忽略。所以 \(d_{1,2}\approx \sqrt{2-2\epsilon_{1,2}}\)。
所以发现,\(i\) 和 \(j\) 的距离只和 \(\epsilon_{i,j}\) 有关,因为其他都带了二次项没影响。所以按照排名直接随便定 \(\epsilon\) 即可。
\(\\\)
Code
// LUOGU_RID: 147661515
// STOOOOOOOOOOOOOOOOOOOOOOOOO hzt CCCCCCCCCCCCCCCCCCCCCCCORZ
#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>
using namespace std;
using LL = long long;
using PII = pair<int, int>;
constexpr int kN = 20 + 1;
int n;
int r[kN][kN];
int main() {
cin.tie(0)->sync_with_stdio(0);
cin >> n;
for (int i = 1, a, b; i <= n * (n - 1) / 2; i++) {
cin >> a >> b;
a > b && (swap(a, b), 0);
r[a][b] = n * (n - 1) / 2 - i;
}
for (int i = 1; i <= n; i++) {
r[i][i] = 1e8;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cout << r[i][j] << ' ';
}
cout << '\n';
}
return 0;
}
E 一般只能发现出结论后证明,这个结论也不是很有意思,就不写题解了。
结论:\((x+10^y)^{x+10^y}\equiv x^x \ (\mod 10^y)\)。