【CSP-S 2022】ストラテジーゲーム
タイトル説明:
小さな L と小さな Q が戦略ゲームをプレイしています。
長さnの配列Aと長さmの配列Bがあり、これに基づいて、Cij =Ai ×Bj を満たす、サイズn×mの行列Cが定義されます。すべての下付き文字は 1 から始まります。
ゲームは合計 q ラウンドあり、ゲームの各ラウンドでは、1≤l1 ≤r1 ≤n, 1 を満たす 4 つのパラメータ l1 、 r1 、 l2 、 r2 が事前に与えられます。 ≤l2 ≤r2 ≤m。
ゲームでは、小さな L が最初に l1 〜 r1 の間の添字 x を選択し、次に小さな Q が l2 〜 r2 の間の添字 y を選択します。このラウンドの 2 人のプレーヤーを定義するスコアは Cxy です。
小さい L の目標は、このスコアをできるだけ大きくすることであり、小さい Q の目標は、このスコアをできるだけ小さくすることです。同時に、両者とも常に最適な戦略を採用できるほど賢いプレイヤーでもあります。
質問したいのですが、2 人の最適な戦略によれば、ゲームの各ラウンドのスコアはいくらになりますか?
入力形式:
最初の行は、配列 A、配列 B の長さとゲーム ラウンド数をそれぞれ表す 3 つの正の整数 n、m、q を入力します。
2 行目: Ai を表す n 個の整数。それぞれ配列 A の要素を表します。
3 行目: Bi を表す m 個の整数。それぞれ配列 B の要素を表します。
次の q 行は、それぞれ 4 つの正の整数を持ち、このゲームの l1、r1、l2、r2 を表します。
出力フォーマット:
合計 q 行を出力します。各行は整数で、ゲームの各ラウンドの最適な戦略に基づくリトル L とリトル Q のスコアをそれぞれ表します。
入力と出力の例:
入力 #1:
3 2 2 0 1 -2 -3 4 1 3 1 2 2 3 2 2
出力 #1:
0 4
入力 #2:
6 4 5 3 -1 -2 1 2 0 1 2 -1 -3 1 6 1 4 1 5 1 4 1 4 1 2 2 6 3 4 2 5 2 3
出力 #2:
0 -2 3 2 -1
指示/ヒント
【例題解説その1】
このデータ セットでは、行列 C は次のようになります。
ゲームの最初のラウンドでは、小さな L が x=2 を選択するか x=3 を選択するかに関係なく、小さな Q には最終スコアをマイナスにする特定の y を選択する方法があります。したがって、スコアは 0 でなければならないため、小さい L では x=1 を選択するのが最適です。
ゲームの 2 ラウンド目では、小さな L は x=2 を選択でき、小さな Q は y=2 しか選択できないため、スコアは 4 になります。
[例 #3]
添付の game/game3.in
対を game/game3.ans
参照してください。
[例 #4]
添付の game/game4.in
対を game/game4.ans
参照してください。
【データ範囲】
すべてのデータについて、1≤n,m,q≤10^5、−10^9≤Ai、Bi≤10^9。各ゲーム ラウンドでは、1≤l1 ≤r1 ≤n、1≤l2 ≤r2 ≤m。
テストポイント番号 | n、m、q ≤ | 特別な条件 |
---|---|---|
1 | 200 | 1、2 |
2 | 200 | 1 |
3 | 200 | 2 |
4〜5 | 200 | なし |
6 | 1000 | 1、2 |
7〜8 | 1000 | 1 |
9〜10 | 1000 | 2 |
11〜12 | 1000 | なし |
13 | 10^5 | 1、2 |
14〜15 | 10^5 | 1 |
16〜17 | 10^5 | 2 |
18〜20 | 10^5 | なし |
このうち特殊な性質 1 は、Ai ,Bi >0 を保証することです。
特別なプロパティ 2 は、ゲームの各ラウンドで l1 = r1 または l2 = r2 のいずれかであることを保証することです。
アイデア:
マトリックスの説明は目隠しです。トピックを翻訳します:
小さい L は a[l1 ⋯r1] で x を選択し、次に小さい Q は b[l2 ⋯r2] で y を選択します。スコアは x×y で、小さい L はスコアを同じくらい大きくしたいと考えています。できるだけ小さく、Q の端数をできるだけ小さくしたいと考えています。スコアを見つけてください。
つまり、小さな L が主導権を持ち、小さな L が選択した後、小さな Q がそこから数値を選択し、Cxy ができるだけ小さくなり、小さな L がすべての可能な Cxy から最大のものを選択します。 。
何が起こるかをシミュレーションしてみましょう。
-
小さい L と小さい Q はどちらも正の整数のみを選択できますが、このとき、小さい L は最大の正の整数を選択し、小さい Q は最小の正の整数を選択します。
-
小Lと小Qはどちらも負の数しか選択できませんが、このとき小Lは最小の負の数を選択し、小Qは最大の負の数を選択します。
-
小さな L は正の整数のみを選択でき、小さな Q は正の整数と負の数の両方を選択できます。このとき、小さな L は最小の正の整数を選択し、小さな Q は最小の負の数を選択します。
-
小さな L は負の数のみを選択でき、小さな Q は正と負の両方の数を選択できます。このとき、小さな L は最大の負の数を選択し、小さな Q は最大の正の整数を選択します。
-
小さな L は正の数と負の数の両方を選択できますが、小さな Q は正の数のみを選択できます。このとき、小さな L は最大の正の数を選択し、小さな Q は最小の正の数を選択します。
-
小さな L は正と負の両方の数を選択できますが、小さな Q は負の数のみを選択できます。このとき、小さな L は最小の負の数を選択し、小さな Q は最大の負の数を選択します。
-
小さな L は正の数と負の数の両方を選択でき、小さな Q は正の数と負の数の両方を選択でき、現時点では答えが異なります。リトル L が正の整数を選択すると、リトル Q は最小の負の数を選択し、リトル L が負の数を選択すると、リトル Q は最大の正の数を選択します。この場合、どのように選択しても、結果は負の数でなければなりません。この負の数をできるだけ大きくしたい場合、小さい L は、数を選択するときに絶対値が比較的小さい数を選択する必要があります。つまり、小さい L は正の数を選択する必要があります。数値の最小値または負の数の最大値です。このとき、小さい Q が選択する数値は、負の最小値と正の最大値、および最大値です。 2 つの場合の値を使用できます。
上記の分析により、最初の 6 つのケースはすべて両側の最大値と最小値から得られ、最後のケースのみが正の数の最小値と負の数の最大値を含むことがわかりました。シーケンスai。
答えを数えるときは、2 つの極値の選択肢から最小値と最大値の場合を取り出し、7 番目の場合があるかどうかを判断して最大値を取るだけで済みます。
2 つのシーケンスの極値のクエリに関しては、変更操作が含まれないため、ST テーブルを使用して 2 つのシーケンスの情報を維持できます。
ST テーブルの前処理の複雑さは O(nlogn+mlogm)、ST テーブルのクエリの複雑さは O(1)、クエリの合計は q 個であるため、合計時間の複雑さは O(nlogn+mlogm+q) です。
完全なコード:
#include <bits/stdc++.h>
#define int long long
inline int read() {
int x = 0;
bool f = true;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-')
f = false;
for (; isdigit(ch); ch = getchar())
x = (x << 1) + (x << 3) + ch - '0';
return f ? x : (~(x - 1));
}
inline int max(int a, int b) {
return a > b ? a : b;
}
inline bool gmx(int &a, int b) {
return b > a ? a = b, true : false;
}
inline int min(int a, int b) {
return a < b ? a : b;
}
const int maxn = (int)1e5 + 5;
const int maxm = (int)1e5 + 5;
const int mlgn = 25;
const int mlgm = 25;
int amx[maxn][mlgn], amn[maxn][mlgn], afx[maxn][mlgn], azn[maxn][mlgn];
int bmx[maxm][mlgm], bmn[maxm][mlgm];
// 6 个 ST 表
// amx:a 的区间最大值,amn:a 的区间最小值,afx:a 的负数区间最大值,azn:a 的非负数区间最小值。
// bmx:b 的区间最大值,bmn:b 的区间最小值。
int lg[maxn];
const int maxinf = LONG_LONG_MAX, mininf = LONG_LONG_MIN;
signed main() {
int n = read(), m = read(), q = read();
for (int i = 1; i <= n; ++i) {
int x = read();
amx[i][0] = amn[i][0] = x;
afx[i][0] = (x < 0 ? x : mininf);
azn[i][0] = (x >= 0 ? x : maxinf);
}
for (int i = 1; i <= m; ++i) {
int x = read();
bmx[i][0] = bmn[i][0] = x;
}
for (int i = 2; i <= max(n, m); ++i)
lg[i] = lg[i >> 1] + 1;
for (int j = 1; j <= lg[n]; ++j) {
for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
int p = i + (1 << (j - 1));
amx[i][j] = max(amx[i][j - 1], amx[p][j - 1]);
afx[i][j] = max(afx[i][j - 1], afx[p][j - 1]);
amn[i][j] = min(amn[i][j - 1], amn[p][j - 1]);
azn[i][j] = min(azn[i][j - 1], azn[p][j - 1]);
}
}
for (int j = 1; j <= lg[m]; ++j) {
for (int i = 1; i + (1 << j) - 1 <= m; ++i) {
int p = i + (1 << (j - 1));
bmx[i][j] = max(bmx[i][j - 1], bmx[p][j - 1]);
bmn[i][j] = min(bmn[i][j - 1], bmn[p][j - 1]);
}
}
while (q--) {
int la = read(), ra = read(), lb = read(), rb = read();
int sa = lg[ra - la + 1], sb = lg[rb - lb + 1];
int pa = ra - (1 << sa) + 1, pb = rb - (1 << sb) + 1;
int amax = max(amx[la][sa], amx[pa][sa]);
int amin = min(amn[la][sa], amn[pa][sa]);
int afmx = max(afx[la][sa], afx[pa][sa]);
int azmn = min(azn[la][sa], azn[pa][sa]);
int bmax = max(bmx[lb][sb], bmx[pb][sb]);
int bmin = min(bmn[lb][sb], bmn[pb][sb]);
int ans = mininf;
gmx(ans, amax * (amax >= 0 ? bmin : bmax));
gmx(ans, amin * (amin >= 0 ? bmin : bmax));
if (afmx != mininf)
gmx(ans, afmx * (afmx >= 0 ? bmin : bmax));
if (azmn != maxinf)
gmx(ans, azmn * (azmn >= 0 ? bmin : bmax));
printf("%lld\n", ans);
}
return 0;
}
要約:
これまでで最も簡単な T2。
最初にこの問題を見たときに、「【】さん、集団試験のゲーム理論は上達しましたか?」と思いました。
しかし、いいえ、これは非常に愚かな欲深い質問です。正しい答えを得るには、考えられるすべての状況を手動でシミュレートするだけで済みます。
トピックリンク:
[CSP-S 2022] 戦略ゲーム - Luogu https://www.luogu.com.cn/problem/P8818