```typescript
/** Fixed-point money helpers: parse, format, and allocate integer cents. */

export function parseAmount(text: string): number {
  if (typeof text !== "string") {
    throw new Error("amount must be a string");
  }
  const match = /^(\d+)(?:\.(\d{2}))?$/.exec(text);
  if (match === null) {
    throw new Error(`malformed amount: ${text}`);
  }
  const whole = Number(match[1]);
  const cents = match[2] === undefined ? 0 : Number(match[2]);
  return whole * 100 + cents;
}

export function formatAmount(cents: number): string {
  if (!Number.isInteger(cents) || cents < 0) {
    throw new Error("cents must be a non-negative integer");
  }
  const whole = Math.floor(cents / 100);
  const rest = String(cents % 100).padStart(2, "0");
  return `${whole}.${rest}`;
}

export function allocateCents(totalCents: number, weights: number[]): number[] {
  if (!Number.isInteger(totalCents) || totalCents < 0) {
    throw new Error("totalCents must be a non-negative integer");
  }
  if (weights.length === 0) {
    throw new Error("weight list cannot be empty");
  }
  const sum = weights.reduce((acc, weight) => acc + weight, 0);
  if (sum <= 0) {
    throw new Error("totalCents must be a non-negative integer and total must not sum to zero");
  }

  // Allocate the full amount first
  const allocated = weights.map((weight, index) => Math.floor(totalCents * weight / sum));
  let remainder = totalCents - allocated.reduce((acc, val) => acc + val, 0);

  // Distribute the remaining cents to shares with the largest remainders, earliest index first on a tie
  const remainingIndices = weights.map((_, index) => index).sort((a, b) => {
    const remainderA = allocated[a] * sum - totalCents;
    const remainderB = allocated[b] * sum - totalCents;
    if (remainderA !== remainderB) return remainderA - remainderB;
    return a - b;
  });

  for (const index of remainingIndices) {
    allocated[index]++;
    remainder--;
    if (remainder === 0) break;
  }

  return allocated;
}
```