T1:序列最大公约数

O(s) 枚举 gcd 即可

代码实现
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, s;
cin >> n >> s;
int ans = 0;
for (int i = 1; i*i <= s; ++i) {
if (s%i != 0) continue;
if (i >= n) ans = max(ans, s/i);
if (s/i >= n) ans = max(ans, i);
}
cout << ans << '\n';
return 0;
}

双倍经验:CF803C

T2:最长回文

经典区间 dp

dp[i][j] 表示对于字符串 s 的子串 s[i:j] 删除若干字符使得 s[i:j] 变成回文串最少需要删除的字符数

代码实现
#include <bits/stdc++.h>
using namespace std;
int main() {
string s;
cin >> s;
int n = s.size();
vector dp(n, vector<int>(n));
for (int span = 2; span <= n; ++span) {
for (int i = 0; i <= n-span; ++i) {
int j = i+span-1;
dp[i][j] = min(dp[i+1][j], dp[i][j-1]) + 1;
if (s[i] == s[j]) {
dp[i][j] = min(dp[i][j], dp[i+1][j-1]);
}
}
}
cout << dp[0][n-1] << '\n';
return 0;
}

T3:香槟塔

注意到,当香槟杯已经满了的话,对我们来说就没用了,我们可以用 std::set 来维护还没有装满的香槟杯,如果装满了就从 std::set 中移除即可

对于操作 1,我们可以利用 std::set 二分找到 x 的最小的位置,然后直接跳到这个位置来模拟即可,而不需要再从 x 开始

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n;
cin >> n;
vector<int> w(n);
rep(i, n) cin >> w[i];
set<int> s;
rep(i, n) s.insert(i);
int q;
cin >> q;
vector<int> ans(n);
rep(qi, q) {
char type; int x;
cin >> type >> x;
--x;
if (type == 'A') {
int y;
cin >> y;
auto it = s.lower_bound(x);
while (it != s.end() and y) {
int i = *it;
int d = min(y, w[i]-ans[i]);
y -= d;
ans[i] += d;
if (ans[i] == w[i]) s.erase(it++);
}
}
else {
cout << ans[x] << '\n';
}
}
return 0;
}

双倍经验:CF371D

T4:极值的和

我们可以固定每个数 ai,并以 ai 作为最大值,求以 ai 为最大值的区间个数,那么我们只需找到距离 i 左边最近的大于它的位置以及右边最近的大于它的位置即可,不妨记做 liri
然后,根据乘法原理,以 ai 为最大值的区间个数就是 (ili)×(rii)

对于 liri 可以用单调栈来求

于是 1ijnmax(ai,ai+1,,aj)=i=1n(ili)×(rii)×ai

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n;
cin >> n;
vector<ll> a(n);
rep(i, n) cin >> a[i];
vector<int> l(n), r(n, n);
stack<int> s;
rep(i, n) {
while (s.size() and a[s.top()] <= a[i]) {
r[s.top()] = i;
s.pop();
}
l[i] = !s.size() ? -1 : s.top();
s.push(i);
}
ll ans = 0;
rep(i, n) {
ans += ll(i-l[i])*(r[i]-i)*a[i];
}
cout << ans << '\n';
return 0;
}

双倍经验:P6503