SRM638D1Med NarrowPassage2

苦手だけどこういうのは好き

問題概要(原文)

$N$ 匹の狼が一列に並んでいる.左から $i$ 番目の狼の大きさは $A_{i}$ である.ある隣り合う狼について $A_{i} + A_{i+1} \leq X$ ならスワップができる. はじめの数列を $(1,2, \ldots , N)$ として,最終的な並べ方は何通りあるか?

考察

$i \rightarrow j$ という関係がいっぱい与えられているときのトポロジカルソートの結果が何通りあるか?という問題である. これは難しい問題なので,もう少し考えよう. 大きさの数列が $B$ で表される狼達ののvalidな並べ方を $f(B)$ とする.

$B$ について, $max(B) + min(B) \leq X$ ならば最小値はどこにでも移動できる.よって, $f(B) = |B| f(B^{\prime})$ ($B^{\prime}$ は最小値を一つ取り除いた数列)となる.

また, $max(B) + min(B) \geq X$ ならば最大値はどこにも移動できない.よって $f(B) = f(B_l^{\prime}) f(B_r^{\prime})$ ($B_l^{\prime}$ は最大値で分割された数列の左側, $B_r^{\prime}$ は右側)となる.

この分割はどのように試してもよい.なので分割は最大でも $N-1$ 回試せば良い.計算量は $O(N^2)$

ソースコード

using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Debug = System.Diagnostics.Debug;
using StringBuilder = System.Text.StringBuilder;
public class NarrowPassage2
{
    public int count(int[] size, int maxSizeSum)
    {
        var n = size.Length;
        const long MOD = 1000000007;
        Func<List<int>, long> dfs = null;
        dfs = a =>
              {
                  if (a.Count <= 1) return 1;
                  var min = a.Min();
                  var max = a.Max();
                  long ret = 0;
                  if (min + max <= maxSizeSum)
                  {
                      var b = new List<int>();
                      foreach (var x in a)
                          if (x == min) min = -1; else b.Add(x);
                      ret = a.Count * dfs(b) % MOD;

                  }
                  else
                  {
                      var b = new List<int>();
                      var c = new List<int>();
                      foreach (var x in a)
                      {
                          if (x == max) max = -1;
                          else
                          {
                              if (max >= 0) b.Add(x);
                              else c.Add(x);
                          }
                      }
                      ret = dfs(b) * dfs(c) % MOD;
                  }
                  return ret;
              };
        var ans = dfs(size.ToList());
        return (int)ans;
    }
}

コメント

  • トポロジカルソートの数え上げに落として考察していて完全にミス
  • こういう再帰的に考えていくのがまだ苦手だなぁ