1995(961div2)
A. Diagonals
给 Vitaly 503 一个方格棋盘,棋盘上有
让我们把
请计算在所有放置
易得此处的对角线是指副对角线,则有
按照从中间往外面贪心的占对角线即可。
void solve() {
int n, k;cin >> n >> k;
int cnt = 0;
for (int i = 1;i <= n;i++) {
if (k >= n - i + 1)cnt++, k -= n - i + 1;
if (i != 1 && k >= n - i + 1)cnt++, k -= n - i + 1;
}
cout << cnt << '\n';
}
B1. Bouquet (Easy Version)
这是问题的简单版本。唯一不同的是,在这个版本中,花朵是通过枚举来指定的。
一个女孩准备过生日,她想买一束最漂亮的花。商店里一共有
这个题太可惜了!一秒钟有思路,双指针(滑动窗口),就是细节没考虑到
法一 :滑动窗口
#define int long long
void solve() {
int n, m;cin >> n >> m;
vector<int> a(n + 1);
for (int i = 1;i <= n;i++)cin >> a[i];
sort(a.begin() + 1, a.end());
int l = 1, r = 1, ans = 0, sum = 0;
while (r <= n && a[r] <= m) {
while (r <= n && sum + a[r] <= m && abs(a[r] - a[l]) <= 1) {
sum += a[r];r++;
ans = max(ans, sum);
if (r > n) {
cout << ans << '\n';return;
}
}
while (l < r && abs(a[r] - a[l]) > 1) {
sum -= a[l];l++;
ans = max(ans, sum);
}
while (l < r && sum + a[r] > m) {
sum -= a[l];l++;
ans = max(ans, sum);
}
}
cout << ans << '\n';
}
法二 :官方题解
首先,我们可以将花瓣数为
请注意
然后我们遍历所有的
求最大值的总复杂度为
#define int long long
void solve() {
int n, m;cin >> n >> m;
map<int, int>mp;
for (int i = 1;i <= n;i++) {
int x;cin >> x;mp[x]++;
}
int ans = 0;
for (auto [x, y] : mp) {
ans = max(ans, x * min(y, m / x));
if (mp.count(x + 1)) {
int z = mp[x + 1];
for (int i = 1;i <= min(y, m / x);i++) {
ans = max(ans, i * x + (x + 1) * min(z, (m - i * x) / (x + 1)));
}
}
}
cout << ans << '\n';
}
B2. Bouquet (Hard Version)
**这是问题的困难版本。唯一不同的是,在这个版本中,不是列出每种花的花瓣数,而是为所有类型的花设置花瓣数和商店中的花的数量。
一个女孩准备过生日,想买一束最漂亮的花。店里一共有
Solution
总的来说和 B1 做法相似,但是不能暴力做了。
首先尽量让
将
- 场上还有
剩余 - 预备的
还有剩余 - 手里的金币还有剩余
#define int long long
void solve() {
int n, m;cin >> n >> m;
vector<int> a(n + 1), c(n + 1);
for (int i = 1;i <= n;i++)cin >> a[i];
map<int, int>mp;
for (int i = 1;i <= n;i++) {
int x;cin >> x; mp[a[i]] = x;
}
int ans = 0;
for (auto [x, y] : mp) {
ans = max(ans, x * min(y, m / x));
if (mp.count(x + 1)) {
int z = mp[x + 1];
int k1 = min(y, m / x);
int k2 = min(z, (m - k1 * x) / (x + 1));
int coins = m - k1 * x - k2 * (x + 1);
int r = min({k1, coins, z - k2});
ans = max(ans, k1 * x + k2 * (x + 1) + r);
}
}
cout << ans << '\n';
}
C. Squaring
ikrpprpp 发现了一个由整数组成的数组
要使数组不递减,最少需要多少次正义行动?
Solution
法一 :正常思路做:
当
当
设到达
非常大,以至于 本来要进行 次操作,而在这里 要到达 需要的操作已经大于等于 ,那么这个时候 自热不需要进行操作 很大,但不至于不需要操作,即 , 本来需要进行 次操作,这里需要进行 次的操作, 则相减则是 需要进行的操作次数 不够大,即 , 本来需要进行 次操作,这里不需要进行操作,则 需要进行 次操作即操作数和 相同。
#define int long long
void solve() {
int n;cin >> n;
vector<int> a(n + 1);
for (int i = 1;i <= n;i++)cin >> a[i];
for (int i = 2;i <= n;i++) {
if (a[i] < a[i - 1] && a[i] == 1) {
cout << "-1\n";return;
}
}
int ans = 0, lst = 0;
for (int i = 1;i <= n;i++) {
int cur = 0;
int x = a[i];
while (x < a[i - 1]) {
x *= x;cur++;
}
x = a[i - 1];
while (lst > 0 && x * x <= a[i]) {
x *= x;lst--;
}
cur += lst;
ans += cur;
lst = cur;
}
cout << ans << '\n';
}
法二 :浮点数做法:
这个做法也是这个 Round 的 EDU 做法
若将数组进行对数处理,即
若
由于
之后的数组只需要看
#define int long long
constexpr double eps = 1e-9;
void solve() {
int n;cin >> n;
vector<double> a(n);
for (auto& i : a)cin >> i;
for (int i = 1;i < n;i++) {
if (a[i - 1] > 1 && a[i] == 1) {
cout << "-1\n";return;
}
}
for (int i = 0;i < n;i++) {
if (a[i] == 1) {
a.erase(a.begin());
} else {
break;
}
}
for (auto& i : a)i = log(log(i));
int ans = 0;
for (int i = 1; i < a.size(); i++) {
double need = a[i - 1] - a[i];
if (need > eps) {
int cnt = 1 + (need - eps) / log(2);
ans += cnt;
a[i] += cnt * log(2);
}
}
cout << ans << '\n';
}
D. Cases
你是一名语言学家,正在研究一种神秘的古代语言。你知道
- 它的单词只由拉丁字母的前
个字母组成。 - 每个单词都有一个大小写,可以通过其最后一个字母明确地确定(不同的字母对应不同的大小写)。例如,单词 "ABACABA "和 "ABA"(如果存在的话)在该语言中具有相同的大小写,因为它们都有相同的词尾 "A",而 "ALICE "和 "BOB "则有不同的大小写。如果语言中没有与某个字母相对应的大小写,则表示该单词不能以该字母结尾。
- 每个单词的长度为
或更少。
您有一个用这种语言写成的文本。不幸的是,由于这种语言非常古老,单词之间没有空格,所有字母都是大写。您想知道这种语言的最少大小写个数是多少。您能找出答案吗?
Solution
SOS DP ->Subset of 状压 DP
1993(963div2) 之后补