#include <bits/stdc++.h>
using namespace std;
/*
Problem: Maximum Display Score by Merging Two Fish Queues
You are given two sequences of fish:
- Tank A of size N
- Tank B of size M
Each fish belongs to some family type.
You want to form one final display row using all fish from both tanks.
Rules:
1. At any step, you can only take the next fish from the front of Tank A
or the next fish from the front of Tank B.
2. The order of fish inside Tank A must remain the same.
3. The order of fish inside Tank B must remain the same.
4. Every fish from both tanks must be used exactly once.
So the final row is just a merge of A and B while preserving the order
inside each individual tank.
------------------------------------------------------------
Scoring:
You are also given a compatibility matrix S.
If a fish of family x is placed immediately before a fish of family y,
then you gain:
S[x][y]
The total display score is the sum of scores of all adjacent pairs
in the final merged row.
------------------------------------------------------------
Task:
Return the maximum possible total display score.
------------------------------------------------------------
Example:
A = [1, 2]
B = [3]
Possible merged rows:
[1, 2, 3] -> score = S[1][2] + S[2][3]
[1, 3, 2] -> score = S[1][3] + S[3][2]
[3, 1, 2] -> score = S[3][1] + S[1][2]
We need the best among all valid merges.
------------------------------------------------------------
Idea:
This is a DP problem.
Let:
dpA[i][j] = best score after using:
- first i fish from A
- first j fish from B
and the last fish placed came from A
dpB[i][j] = same idea, but the last fish placed came from B
From each state, we try to place the next fish from A or B
and update the score depending on which fish was placed just before it.
Time Complexity: O(N * M)
Space Complexity: O(N * M)
*/
long long maxDisplayScore(vector<int>& A, vector<int>& B, vector<vector<long long>>& S) {
int n = (int)A.size();
int m = (int)B.size();
// A very small value to represent an impossible state
const long long NEG = -(1LL << 60);
/*
dpEndA[i][j] = best score after taking:
- first i fish from A
- first j fish from B
and the last fish in the merged sequence is A[i - 1]
*/
vector<vector<long long>> dpEndA(n + 1, vector<long long>(m + 1, NEG));
/*
dpEndB[i][j] = best score after taking:
- first i fish from A
- first j fish from B
and the last fish in the merged sequence is B[j - 1]
*/
vector<vector<long long>> dpEndB(n + 1, vector<long long>(m + 1, NEG));
// Starting with the first fish from A gives score 0
if (n > 0) dpEndA[1][0] = 0;
// Starting with the first fish from B also gives score 0
if (m > 0) dpEndB[0][1] = 0;
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= m; j++) {
// Try to make the current merged sequence end with A[i - 1]
if (i > 0) {
// Previous fish also came from A
if (i > 1) {
dpEndA[i][j] = max(
dpEndA[i][j],
dpEndA[i - 1][j] + S[A[i - 2]][A[i - 1]]
);
}
// Previous fish came from B
if (j > 0) {
dpEndA[i][j] = max(
dpEndA[i][j],
dpEndB[i - 1][j] + S[B[j - 1]][A[i - 1]]
);
}
}
// Try to make the current merged sequence end with B[j - 1]
if (j > 0) {
// Previous fish also came from B
if (j > 1) {
dpEndB[i][j] = max(
dpEndB[i][j],
dpEndB[i][j - 1] + S[B[j - 2]][B[j - 1]]
);
}
// Previous fish came from A
if (i > 0) {
dpEndB[i][j] = max(
dpEndB[i][j],
dpEndA[i][j - 1] + S[A[i - 1]][B[j - 1]]
);
}
}
}
}
// If both sequences are empty
if (n == 0 && m == 0) return 0;
// If only B has fish
if (n == 0) return dpEndB[0][m];
// If only A has fish
if (m == 0) return dpEndA[n][0];
// Otherwise answer can end with either A or B
return max(dpEndA[n][m], dpEndB[n][m]);
}