C. Basil's Garden(dp)
发现最后一个变为 0 的一定是第一个,对于每一个位置而言,如果它后面的位置没变为 0 ,那么它就不可能变为 0,所以它变为 0 的时刻最小应该是在它后一个位置变为 0 的时刻加 1,如果这个位置太高的话,就需要 a[i]
个时间变为 0,所以当前位置变为 0 的时刻就是二者取最大值
设计 dp[i]
表示第 i 个位置变为 0 的时刻,有转移方程:dp[i] = max(dp[i + 1] + 1, a[i])
cpp
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int maxn = 1e6 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i ++ ) cin >> a[i];
reverse(a.begin() + 1, a.end());
vector<int> ans(n + 1);
ans[1] = a[1];
for (int i = 2; i <= n; i ++ ) ans[i] = max(ans[i - 1] + 1, a[i]);
cout << ans[n] << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
}
D. World is Mine(dp)
关于博弈问题的一般思路:
首先思考二者分别的最优策略:
Alice 一定是能取小的就取小的
Bob 需要取一定的数使得 Alice 没法取这个数
设计 dp[i][j]
表示 Bob 在前 i 种数里选完了 j 种(注意是种不是个)的时候需要进行的操作次数
如果不取第 i + 1 种的话, dp[i + 1][j + 1]
等于 dp[i][j + 1]
如果要取第 i + 1 种,首先需要满足一个条件,即 dp[i][j] + 第i+1种数字的个数 <= i - j
,因为要保证 Alice 的操作次数比 Bob 多,在满足该条件的基础下,dp[i + 1][j + 1]
等于 min(dp[i + 1][j + 1], dp[i][j] + 第i+1种数字的个数)
cpp
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int maxn = 1e6 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n;
cin >> n;
vector<int> cnt(n + 1);
for (int i = 0; i < n; i ++ )
{
int x; cin >> x;
cnt[x] ++ ;
}
vector<int> v;
for (int i = 1; i <= n; i ++ )
{
if (cnt[i] > 0) v.push_back(cnt[i]);
}
int m = v.size();
vector<vector<int>> dp(m + 1, vector<int>(m + 1, INF));
for (int i = 0; i <= m; i ++ ) dp[i][0] = 0;
for (int i = 0; i < m; i ++ )
{
for (int j = 0; j < i; j ++ )
{
dp[i + 1][j + 1] = min(dp[i + 1][j + 1], dp[i][j + 1]);
if (dp[i][j] + v[i] <= i - j)
{
dp[i + 1][j + 1] = min(dp[i + 1][j + 1], dp[i][j] + v[i]);
}
}
}
int ans = INF;
for (int i = 0; i <= m; i ++ )
{
if (dp[m][i] != INF) ans = min(ans, m - i);
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
}