Loading

解题报告 HZOI DP 专题 2024/11/23

开题顺序主观由易到难。


Omkar and Password

题面翻译

题目描述

多组询问,每次给出一个长度为 \(n\) 的序列 \(a\),对于两个相邻的且不相同的数,你可以将他们合并起来,即将这两个数替换成它们的和。

注意到,你每次进行一次操作后,序列长度会 \(-1\),现在你可以随意进行若干次操作,问最后序列长度最短是多少。

题目描述

Lord Omkar has permitted you to enter the Holy Church of Omkar! To test your worthiness, Omkar gives you a password which you must interpret!

A password is an array $ a $ of $ n $ positive integers. You apply the following operation to the array: pick any two adjacent numbers that are not equal to each other and replace them with their sum. Formally, choose an index $ i $ such that $ 1 \leq i < n $ and $ a_{i} \neq a_{i+1} $ , delete both $ a_i $ and $ a_{i+1} $ from the array and put $ a_{i}+a_{i+1} $ in their place.

For example, for array $ [7, 4, 3, 7] $ you can choose $ i = 2 $ and the array will become $ [7, 4+3, 7] = [7, 7, 7] $ . Note that in this array you can't apply this operation anymore.

Notice that one operation will decrease the size of the password by $ 1 $ . What is the shortest possible length of the password after some number (possibly $ 0 $ ) of operations?

输入格式

Each test contains multiple test cases. The first line contains the number of test cases $ t $ ( $ 1 \le t \le 100 $ ). Description of the test cases follows.

The first line of each test case contains an integer $ n $ ( $ 1 \leq n \leq 2 \cdot 10^5 $ ) — the length of the password.

The second line of each test case contains $ n $ integers $ a_{1},a_{2},\dots,a_{n} $ ( $ 1 \leq a_{i} \leq 10^9 $ ) — the initial contents of your password.

The sum of $ n $ over all test cases will not exceed $ 2 \cdot 10^5 $ .

输出格式

For each password, print one integer: the shortest possible length of the password after some number of operations.

样例 #1

样例输入 #1

2
4
2 1 3 1
2
420 420

样例输出 #1

1
2

提示

In the first test case, you can do the following to achieve a length of $ 1 $ :

Pick $ i=2 $ to get $ [2, 4, 1] $

Pick $ i=1 $ to get $ [6, 1] $

Pick $ i=1 $ to get $ [7] $

In the second test case, you can't perform any operations because there is no valid $ i $ that satisfies the requirements mentioned above.

你说得对,但是 gzxworld 说得对。
对于一个全相等的序列,显然有答案为 \(n\)
对于一个不全相等的序列,我们不妨设其最大值为 \(p\)\(p\) 显然可以合并,记 \(p\) 与其任意一侧合并产生的数为 \(q\),因为 \(\forall a_i , 1 \le a_i \le 10^9\),有 \(p \lt q\),即 \(q\) 成为新的最大值。
重复以上过程可知序列最终会剩下一个 \(q\),即答案为 \(1\)
多测记得清空。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 200000 + 10;

int T, n, a[maxn];
bool flag = true;

int main()
{
   ios::sync_with_stdio(false);
   cin.tie(0), cout.tie(0);
   cin >> T;
   while (T--)
   {
       cin >> n;
       cin >> a[1];
       for (int i = 2; i <= n; i++)
       {
           cin >> a[i];
           if (a[i] != a[i - 1])
               flag = false;
       }
       if (flag)
           cout << n << endl;
       else
           cout << 1 << endl;
       memset(a, 0, sizeof a);
       flag = true;
   }
   return 0;
}

Game on Sum (Easy Version)

题面翻译

Alice 和 Bob 正在玩一个游戏,游戏分为 \(n\) 个回合,Alice 和 Bob 要轮流对一个数 \(x\) 进行操作,已知这个数初始值是 \(0\)

具体每个回合的行动规则如下:

  1. Alice 选择一个在区间 \([0,k]\) 之间的实数 \(t\)
  2. Bob 可以选择让 \(x\) 变成 \(x+t\) 或者 \(x-t\),但是 Bob 在 \(n\) 个回合之内至少选择 \(m\) 次让 \(x\) 变成 \(x+t\)

Alice想让最终的 \(x\) 最大,Bob 想让最终的 \(x\) 最小。

已知双方均采用最优策略,求最终的 \(x\) 值(对 \(10^9+7\) 取模)。

数据范围保证:\(1\le m\le n\le 2000,k\le10^9+7\)

题目描述

This is the easy version of the problem. The difference is the constraints on $ n $ , $ m $ and $ t $ . You can make hacks only if all versions of the problem are solved.

Alice and Bob are given the numbers $ n $ , $ m $ and $ k $ , and play a game as follows:

The game has a score that Alice tries to maximize, and Bob tries to minimize. The score is initially $ 0 $ . The game consists of $ n $ turns. Each turn, Alice picks a real number from $ 0 $ to $ k $ (inclusive) which Bob either adds to or subtracts from the score of the game. But throughout the game, Bob has to choose to add at least $ m $ out of the $ n $ turns.

Bob gets to know which number Alice picked before deciding whether to add or subtract the number from the score, and Alice gets to know whether Bob added or subtracted the number for the previous turn before picking the number for the current turn (except on the first turn since there was no previous turn).

If Alice and Bob play optimally, what will the final score of the game be?

输入格式

The first line of the input contains a single integer $ t $ ( $ 1 \le t \le 1000 $ ) — the number of test cases. The description of test cases follows.

Each test case consists of a single line containing the three integers, $ n $ , $ m $ , and $ k $ ( $ 1 \le m \le n \le 2000, 0 \le k < 10^9 + 7 $ ) — the number of turns, how many of those turns Bob has to add, and the biggest number Alice can choose, respectively.

It is guaranteed that the sum of $ n $ over all test cases does not exceed $ 2000 $ .

输出格式

For each test case output a single integer number — the score of the optimal game modulo $ 10^9 + 7 $ .

Formally, let $ M = 10^9 + 7 $ . It can be shown that the answer can be expressed as an irreducible fraction $ \frac{p}{q} $ , where $ p $ and $ q $ are integers and $ q \not \equiv 0 \pmod{M} $ . Output the integer equal to $ p \cdot q^{-1} \bmod M $ . In other words, output such an integer $ x $ that $ 0 \le x < M $ and $ x \cdot q \equiv p \pmod{M} $ .

样例 #1

样例输入 #1

7
3 3 2
2 1 10
6 3 10
6 4 10
100 1 1
4 4 0
69 4 20

样例输出 #1

6
5
375000012
500000026
958557139
0
49735962

提示

In the first test case, the entire game has $ 3 $ turns, and since $ m = 3 $ , Bob has to add in each of them. Therefore Alice should pick the biggest number she can, which is $ k = 2 $ , every turn.

In the third test case, Alice has a strategy to guarantee a score of $ \frac{75}{8} \equiv 375000012 \pmod{10^9 + 7} $ .

In the fourth test case, Alice has a strategy to guarantee a score of $ \frac{45}{2} \equiv 500000026 \pmod{10^9 + 7} $ .

显然 Bob 会选择恰好 \(m\) 次让 \(x\) 变成 \(x+t\)
考虑 DP 状态设计,记 \(dp_{i,j}\) 表示进行了 \(i\) 轮,选择了 \(j\) 次加法后的答案。
注意到当 Alice 的操作完成以后,Bob 的操作才可以确定,那么 Alice 的操作应该让 Bob 无论如何选择都得到较大的结果。
所以先考虑 Bob 的状态转移,显然有:

\[dp_{i,j}=\min(dp_{i-1,j-1}+t,dp_{i-1,j}-t) \]

那么对于 Alice,可知其希望:

\[dp_{i-1,j-1}+t=dp_{i-1,j}-t \]

解得:

\[t=\dfrac{dp_{i-1,j}-dp_{i-1,j-1}}{2} \]

代入上式有:

\[dp_{i,j}=\dfrac{dp_{i-1,j-1}+dp_{i-1,j}}{2} \]

显然边界状态为:\(dp_{i,0}=0,dp_{i,i}=i\times k\)
\(dp_{n,m}\) 即为所求。

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn = 2000 + 10;
const int mod = 1000000000 + 7;
const int inv = 500000004; // 2 在 mod 1e9+7 意义下的乘法逆元

int T, n, m, k;
int dp[maxn][maxn];

signed main()
{
   ios::sync_with_stdio(false);
   cin.tie(0), cout.tie(0);
   cin >> T;
   while (T--)
   {
       cin >> n >> m >> k;
       for (int i = 1; i <= n; i++)
           dp[i][i] = i * k % mod;
       for (int i = 2; i <= n; i++)
       {
           for (int j = 1; j <= i - 1; j++)
               dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1]) % mod * inv % mod;
       }
       cout << dp[n][m] << endl;
   }
   return 0;
}

\(O(Tnm)\) 3 秒 4e9 居然能过。


Birds

题面翻译

一条直线上有 \(n\) 棵树,第 \(i\) 棵树上有 \(c_i\) 只鸟。

在第 \(i\) 棵树底下召唤一只鸟的魔法代价是 \(cost_i\)。每召唤一只鸟,魔法上限会增加 \(B\)。从一棵树走到另一棵树,会增加魔法 \(X\)。一开始的魔法和魔法上限都是 \(W\)

问最多能够召唤的鸟的个数。

题目描述

Apart from plush toys, Imp is a huge fan of little yellow birds!

To summon birds, Imp needs strong magic. There are $ n $ trees in a row on an alley in a park, there is a nest on each of the trees. In the $ i $ -th nest there are $ c_{i} $ birds; to summon one bird from this nest Imp needs to stay under this tree and it costs him $ cost_{i} $ points of mana. However, for each bird summoned, Imp increases his mana capacity by $ B $ points. Imp summons birds one by one, he can summon any number from $ 0 $ to $ c_{i} $ birds from the $ i $ -th nest.

Initially Imp stands under the first tree and has $ W $ points of mana, and his mana capacity equals $ W $ as well. He can only go forward, and each time he moves from a tree to the next one, he restores $ X $ points of mana (but it can't exceed his current mana capacity). Moving only forward, what is the maximum number of birds Imp can summon?

输入格式

The first line contains four integers $ n $ , $ W $ , $ B $ , $ X $ ( $ 1<=n<=10{3},0<=W,B,X<=10 $ ) — the number of trees, the initial points of mana, the number of points the mana capacity increases after a bird is summoned, and the number of points restored when Imp moves from a tree to the next one.

The second line contains $ n $ integers $ c_{1},c_{2},...,c_{n} $ ( $ 0<=c_{i}<=10^{4} $ ) — where $ c_{i} $ is the number of birds living in the $ i $ -th nest. It is guaranteed that .

The third line contains $ n $ integers $ cost_{1},cost_{2},...,cost_{n} $ ( $ 0<=cost_{i}<=10^{9} $ ), where $ cost_{i} $ is the mana cost to summon a bird from the $ i $ -th nest.

输出格式

Print a single integer — the maximum number of birds Imp can summon.

样例 #1

样例输入 #1

2 12 0 4
3 4
4 2

样例输出 #1

6

样例 #2

样例输入 #2

4 1000 10 35
1 2 4 5
1000 500 250 200

样例输出 #2

5

样例 #3

样例输入 #3

2 10 7 11
2 10
6 1

样例输出 #3

11

提示

In the first sample base amount of Imp's mana is equal to $ 12 $ (with maximum capacity also equal to $ 12 $ ). After he summons two birds from the first nest, he loses $ 8 $ mana points, although his maximum capacity will not increase (since $ B=0 $ ). After this step his mana will be $ 4 $ of $ 12 $ ; during the move you will replenish $ 4 $ mana points, and hence own $ 8 $ mana out of $ 12 $ possible. Now it's optimal to take $ 4 $ birds from the second nest and spend $ 8 $ mana. The final answer will be — $ 6 $ .

In the second sample the base amount of mana is equal to $ 1000 $ . The right choice will be to simply pick all birds from the last nest. Note that Imp's mana doesn't restore while moving because it's initially full.

这题怎么长得和背包似的。
一个显然的暴力 DP 是记 \(dp_{i,j,k}\) 表示在第 \(i\) 棵树下,魔法值为 \(j\),魔法值上限为 \(k\) 时鸟的最大数量。
然后非常愉快地,\(j\)\(k\) 全爆了。
注意到魔法值上限可以表示为 \(k=W+dp_{i,j,k} \times B\),即 \(k\) 是冗余数据,可以省去,而 \(j\) 处理不了。
于是我们可以交换下标和值,得到:\(dp_{i,j}\) 表示在第 \(i\) 棵树下,有 \(j\) 只鸟时能量的最大值。
写出状态转移方程:

\[dp_{i,j}=\max_{k=0}^{c_i}\{dp_{i-1,j-k}-k\times cost_i+X\} \]

并且考虑到魔法值的上下界,有 \(dp_{i,j} \in [0,W+B\times j]\)

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1000 + 10;
const int maxc = 10000 + 10;

int n, w, b, x;
int c[maxn], cost[maxn];
int pre[maxn];
int dp[maxn][maxc];

int main()
{
   ios::sync_with_stdio(false);
   cin.tie(0), cout.tie(0);
   cin >> n >> w >> b >> x;
   for (int i = 1; i <= n; i++)
   {
       cin >> c[i];
       pre[i] = pre[i - 1] + c[i];
   }
   for (int i = 1; i <= n; i++)
       cin >> cost[i];
   memset(dp, -1, sizeof dp);
   dp[0][0] = w;
   for (int i = 1; i <= n; i++)
       for (int j = 0; j <= pre[i]; j++)
           for (int k = 0; k <= c[i] && k <= j; k++)
           {
               if (dp[i - 1][j - k] == -1 || dp[i - 1][j - k] - k * cost[i] < 0)
                   continue;
               dp[i][j] = min(max(dp[i][j], dp[i - 1][j - k] - k * cost[i] + x), w + b * j);
           }
   for (int i = pre[n]; i >= 1; i--)
       if (dp[n][i] != -1)
       {
           cout << i << endl;
           break;
       }
   return 0;
}

吃两发罚时。
第一次没开 long long
第二次输出时没有考虑到一只鸟都没有的 corner case。
所以输出应该这么写:

int ans = 0;
   for (int i = 1; i <= pre[n]; i++)
   {
       if (dp[n][i] != -1)
           ans = max(ans, dp[n][i]);
   }
   cout << ans << endl;
posted @ 2024-11-24 10:56  Merlin_Meow  阅读(28)  评论(0)    收藏  举报
Sakana Widget 自定义角色自适应示例