following is the code for sentence alignment, I found that this algorithm will prefer the two (1,1) alignment operation instead of one (2,2) operation, even if the (2,2) operation is the correct one.
The problem lay inside the fucntion `compute_dp_table`, more specific is how to computet alignment score. As you can see that the alignment score for many-to-many alignment is averge similarity of all pairs,
which doesn't take number of sentences of source and target, and it'll cause algorithm to select two (1,1) instead of one (2,2), please modify the algorithm to fix this issue:

```python
import numpy as np
import sentence_transformers
import torch
from numba import jit

N = 10000


def timeit(func):
    """Decorator to time function execution."""
    import time

    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Execution time for {func.__name__}: {end_time - start_time:.4f} seconds")
        return result

    return wrapper


def get_source_sentences() -> list[str]:
    with open("en.tmp.txt", encoding="utf-8") as f:
        return [line.strip() for line in f if line.strip()]


def get_target_sentences() -> list[str]:
    with open("zh.tmp.txt", encoding="utf-8") as f:
        return [line.strip() for line in f if line.strip()]


@timeit
@jit(nopython=True, cache=True, fastmath=True)
def compute_dp_table(cosine_similarities: np.ndarray, m: int, n: int, max_span: int = 3):
    """Compute DP table supporting many-to-many alignments up to max_span."""
    dp_table = np.zeros((m + 1, n + 1), dtype=np.float32)
    dp_action = np.zeros((m + 1, n + 1, 2), dtype=np.int8)

    # Initialize with negative infinity for impossible states
    dp_table[:, :] = -np.inf
    dp_table[0, 0] = 0.0

    for i in range(m + 1):
        for j in range(n + 1):
            if i == 0 and j == 0:
                continue

            best_score = -np.inf
            best_action = (0, 0)

            # Try all possible alignment spans
            for di in range(max_span + 1):
                for dj in range(max_span + 1):
                    # Skip (0,0) as it means no progress
                    if di == 0 and dj == 0:
                        continue

                    # Check bounds
                    if i - di < 0 or j - dj < 0:
                        continue

                    # Calculate score for this alignment
                    prev_score = dp_table[i - di, j - dj]
                    if prev_score == -np.inf:
                        continue

                    # Compute alignment score
                    if di > 0 and dj > 0:
                        # Many-to-many alignment: average similarity of all pairs
                        alignment_score = 0.0
                        count = 0
                        for si in range(di):
                            for sj in range(dj):
                                if i - di + si < m and j - dj + sj < n:
                                    alignment_score += cosine_similarities[i - di + si, j - dj + sj]
                                    count += 1
                        if count > 0:
                            # Use average similarity, with penalty for unbalanced alignments
                            balance_penalty = 1.0 - abs(di - dj) * 0.1
                            alignment_score = (alignment_score / count) * balance_penalty
                        else:
                            alignment_score = 0.0
                    else:
                        # Skip alignment (either di=0 or dj=0)
                        alignment_score = -0.1  # Small penalty for skipping

                    current_score = prev_score + alignment_score

                    if current_score > best_score:
                        best_score = current_score
                        best_action = (di, dj)

            dp_table[i, j] = best_score
            dp_action[i, j, 0] = best_action[0]
            dp_action[i, j, 1] = best_action[1]

    return dp_action


@timeit
@jit(nopython=True, cache=True)
def backtrack(dp_action: np.ndarray, m: int, n: int) -> list[tuple[int, int, int, int]]:
    """Backtrack to find optimal alignment path."""
    result = []

    i, j = m, n
    while i > 0 or j > 0:
        action_i = dp_action[i, j, 0]
        action_j = dp_action[i, j, 1]

        if action_i == 0 and action_j == 0:
            # This shouldn't happen with valid DP table
            break

        result.append((i - action_i, i, j - action_j, j))

        i -= action_i
        j -= action_j

    return result


class SentenceAligner:
    def __init__(self, model_name: str = "sentence-transformers/LaBSE"):
        self.model = sentence_transformers.SentenceTransformer(model_name)
        # Enable GPU if available
        if torch.cuda.is_available():
            self.model = self.model.cuda()
        # Set model to eval mode
        self.model.eval()

    def encode_sentences(self, sentences: list[str], batch_size: int = 128) -> np.ndarray:
        """Encode sentences with optimizations."""
        with torch.no_grad():
            embeddings = self.model.encode(
                sentences,
                batch_size=batch_size,
                show_progress_bar=False,
                convert_to_numpy=True,
                normalize_embeddings=True,
                convert_to_tensor=False,
                device=self.model.device,
            )
        return embeddings.astype(np.float32)

    def get_embeddings_map(
        self,
        source_sentences: list[str],
        target_sentences: list[str],
        batch_size: int = 128,
    ) -> dict[str, np.ndarray]:
        sentences = list(set(source_sentences + target_sentences))
        embeddings = self.encode_sentences(sentences, batch_size)
        embeddings_map = {sent: emb for sent, emb in zip(sentences, embeddings)}
        return embeddings_map

    def build_embeddings(
        self,
        sentences: list[str],
        embedding_map: dict[str, np.ndarray],
    ) -> np.ndarray:
        """Build embeddings from the embedding map."""
        embeddings = np.array([embedding_map[sent] for sent in sentences], dtype=np.float32)
        return embeddings

    @timeit
    def align_sentences(
        self,
        source_sentences: list[str],
        target_sentences: list[str],
        batch_size: int = 128,
        max_span: int = 3,
    ) -> list[tuple[list[str], list[str]]]:
        """Align sentences using optimized dynamic programming with many-to-many support."""
        m = len(source_sentences)
        n = len(target_sentences)
        if m == 0 or n == 0:
            return []
        embedding_map = self.get_embeddings_map(source_sentences, target_sentences, batch_size)
        src_embeddings = self.build_embeddings(source_sentences, embedding_map)
        tgt_embeddings = self.build_embeddings(target_sentences, embedding_map)
        cosine_similarities = self.compute_cosine_similarity(src_embeddings, tgt_embeddings)
        dp_action = compute_dp_table(cosine_similarities, m, n, max_span)
        alignment_indices = backtrack(dp_action, m, n)
        aligned_pairs = self.generate_aligned_pairs(source_sentences, target_sentences, alignment_indices)
        return aligned_pairs

    @timeit
    def compute_cosine_similarity(self, src_embeddings, tgt_embeddings):
        return src_embeddings @ tgt_embeddings.T

    @timeit
    def generate_aligned_pairs(self, source_sentences, target_sentences, alignment_indices):
        aligned_pairs = []
        for src_start, src_end, tgt_start, tgt_end in reversed(alignment_indices):
            src_group = source_sentences[src_start:src_end]
            tgt_group = target_sentences[tgt_start:tgt_end]
            aligned_pairs.append((src_group, tgt_group))
        return aligned_pairs


def main():
    # Load sentences
    source_sentences = get_source_sentences()[:N]
    target_sentences = get_target_sentences()[:N]

    print(f"Aligning {len(source_sentences)} source sentences with {len(target_sentences)} target sentences...")

    # Create aligner instance (reuse model for multiple alignments)
    aligner = SentenceAligner()

    # Get aligned pairs
    aligned_pairs = aligner.align_sentences(source_sentences, target_sentences)

    print(f"Found {len(aligned_pairs)} aligned pairs.")

    # Print results
    for idx, (source_sent, target_sent) in enumerate(aligned_pairs):
        print(f"Aligned Pair {idx + 1}:")
        print(f"Source: {' '.join(source_sent)}")
        print(f"Target: {' '.join(target_sent)}")
        print()


if __name__ == "__main__":
    main()
```