CF1792
贪心,从小到大排序。
对于当前怪物,如果血量大于 \(1\),则直接杀死,否则和下一个怪物各扣一滴血。
复杂度 \(O(n\log n)\)。
#include <bits/stdc++.h>
using namespace std;
const int N = 100 + 5;
int T, n, a[N];
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> T;
while (T--) {
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
sort(a + 1, a + n + 1);
int cnt = 0;
for (int i = 1; i <= n; ++i) {
if (a[i] == 1) {
--a[i]; --a[i + 1];
++cnt;
} else if (a[i] > 1) ++cnt;
}
cout << cnt << endl;
}
return 0;
}
还是贪心。
首先我们可以把两人都喜欢的节目 \(a_1\) 安排上,然后一个 \(a_2\) 一个 \(a_3\) 使得两人的心情值不变。
最后把 \(a_2\),\(a_3\),\(a_4\) 中剩下的尽可能安排上。
复杂度 \(O(1)\)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int T;
ll a, b, c, d;
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> T;
while (T--) {
cin >> a >> b >> c >> d;
if (a == 0) {
cout << 1 << endl;
continue;
}
ll ans = a;
if (b > c) ans += c * 2, b -= c, c = 0;
else ans += b * 2, c -= b, b = 0;
ans += min(a, b + c + d);
if(b + c + d > a) ++ans;
cout << ans << endl;
}
return 0;
}
又是贪心。
我们假设最后选了 \([1,x]\) 和 \([n-x+1,n]\) 中所有的数,完成了序列的排序。
那么只有 \((x,n-x+1)\) 在对应的位置上时才能成立。
于是我们可以记录原始数组中每个数的位置,然后从中间部分向两侧拓展,看 \((x,n-x+1)\) 最长为多少即可。
复杂度 \(O(n)\)。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int T, n, a[N], w[N];
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> T;
while (T--) {
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
w[a[i]] = i;
}
int l = n / 2, r = (n + 3) / 2, ans = n / 2;
while (l >= 1 && w[l] < w[l + 1] && w[r - 1] < w[r]) --l, ++r, --ans;
cout << ans << endl;
}
return 0;
}
感觉思维难度比 \(C\) 题要小。
我们发现 \(m\) 很小,考虑把一个序列的每个前缀压缩成一个 \(11\) 进制的数(注意是 \(11\) 进制!),然后全部放到 map
里。
然后对于每一个序列,我们只需要找出与其完全匹配的数组 \(x\),即 \(p \cdot x\) 的美丽度为 \(m\)。然后枚举 \(x\) 的前缀,看 map
中中有没有即可。
复杂度 \(O(n\log n)\)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e4 + 5, N2 = 10 + 5;
int T, n, m, a[N][N2], w[N];
ll val[N];
map<ll, int> mp;
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> T;
while (T--) {
cin >> n >> m;
mp.clear();
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
cin >> a[i][j];
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
w[a[i][j]] = j;
}
ll tmp = 0;
for (int j = 1; j <= m; ++j) {
tmp = tmp * 11 + w[j];
mp[tmp] = 1;
}
}
for (int i = 1; i <= n; ++i) {
ll tmp = 0, ans = 0;
for (int j = 1; j <= m; ++j) {
tmp = tmp * 11 + a[i][j];
if (mp[tmp]) ans = j;
}
cout << ans << endl;
}
}
return 0;
}
正着想有点难,我们考虑找到最大的行,然后对应的列就是答案。
首先我们用 \(O(\sqrt m_1+\sqrt m_2)\) 的时间找出 \(m\) 的所有质因数,然后 dfs 出 \(m\) 的所有约数。
定义 \(f_i\) 为 \(i\) 的小于 \(n\) 的所有约数中最大的约数。
枚举 \(i\) 的每个约数 \(j\),可得到转移方程:
那么最后的答案为 \(\sum\limits_{i\vert n}^{n}[\frac{i}{f_i}\le n]\) 和 \(\bigoplus\limits_{i|n}^{n}[\frac{i}{f_i}\le n]\frac{i}{f_i}\)。
复杂度 \(O(能过)\)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
ll T, n, m1, m2, p[N], num[N], yue[N], f[N], cnt, cnt2, ans, yh = 0;
map<ll, ll> mp;
void get(ll x) {
for (ll i = 2; i <= sqrt(x); ++i) {
while (x % i == 0) {
++mp[i]; x /= i;
}
}
if (x != 1) ++mp[x];
}
void dfs(int cur, ll val) {
if (cur > cnt) {
yue[++cnt2] = val;
return;
}
for (int i = 0; i <= num[cur]; ++i) {
dfs(cur + 1, val);
val *= p[cur];
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> T;
while (T--) {
mp.clear(); cnt = cnt2 = ans = yh = 0;
cin >> n >> m1 >> m2; get(m1); get(m2);
map<ll, ll>::iterator it;
for (it = mp.begin(); it != mp.end(); ++it) {
p[++cnt] = (*it).first;
num[cnt] = (*it).second;
}
dfs(1, 1);
sort(yue + 1, yue + cnt2 + 1);
for (int i = 1; i <= cnt2; ++i) f[i] = yue[i] <= n?yue[i]:0;
for (int i = 1; i <= cnt2; ++i) {
for (int j = 1; j <= cnt; ++j) if (yue[i] % p[j] == 0) f[i] = max(f[i], f[lower_bound(yue + 1, yue + cnt2 + 1, yue[i] / p[j]) - yue]);
if (yue[i] / f[i] <= n) {
++ans;
yh ^= yue[i] / f[i];
}
}
cout << ans << " " << yh << endl;
}
return 0;
}