結果

問題 No.1204 お菓子配り-FINAL
ユーザー 👑 hos.lyrichos.lyric
提出日時 2020-08-30 04:07:47
言語 D
(dmd 2.106.1)
結果
WA  
実行時間 -
コード長 9,163 bytes
コンパイル時間 1,777 ms
コンパイル使用メモリ 165,052 KB
実行使用メモリ 6,948 KB
最終ジャッジ日時 2024-06-22 08:39:28
合計ジャッジ時間 4,630 ms
ジャッジサーバーID
(参考情報)
judge3 / judge2
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 WA -
testcase_01 WA -
testcase_02 WA -
testcase_03 WA -
testcase_04 WA -
testcase_05 WA -
testcase_06 WA -
testcase_07 WA -
testcase_08 WA -
testcase_09 WA -
testcase_10 WA -
testcase_11 WA -
testcase_12 WA -
testcase_13 WA -
testcase_14 WA -
testcase_15 WA -
testcase_16 WA -
testcase_17 WA -
testcase_18 WA -
testcase_19 WA -
testcase_20 WA -
testcase_21 WA -
testcase_22 WA -
testcase_23 WA -
testcase_24 WA -
testcase_25 WA -
testcase_26 WA -
testcase_27 WA -
testcase_28 WA -
testcase_29 WA -
testcase_30 WA -
testcase_31 WA -
testcase_32 WA -
testcase_33 WA -
testcase_34 WA -
testcase_35 WA -
testcase_36 WA -
testcase_37 WA -
testcase_38 WA -
testcase_39 WA -
testcase_40 WA -
testcase_41 WA -
testcase_42 WA -
testcase_43 WA -
testcase_44 WA -
testcase_45 WA -
testcase_46 WA -
testcase_47 WA -
testcase_48 WA -
testcase_49 WA -
testcase_50 WA -
testcase_51 WA -
testcase_52 WA -
testcase_53 WA -
testcase_54 WA -
testcase_55 WA -
testcase_56 WA -
testcase_57 WA -
testcase_58 WA -
testcase_59 WA -
testcase_60 WA -
testcase_61 WA -
testcase_62 WA -
testcase_63 WA -
testcase_64 WA -
testcase_65 WA -
testcase_66 WA -
testcase_67 WA -
testcase_68 WA -
testcase_69 WA -
testcase_70 WA -
testcase_71 WA -
testcase_72 WA -
testcase_73 WA -
testcase_74 WA -
testcase_75 WA -
testcase_76 WA -
testcase_77 WA -
testcase_78 WA -
testcase_79 WA -
testcase_80 WA -
testcase_81 WA -
testcase_82 WA -
testcase_83 WA -
testcase_84 WA -
testcase_85 WA -
testcase_86 WA -
testcase_87 WA -
testcase_88 WA -
testcase_89 WA -
testcase_90 WA -
testcase_91 WA -
testcase_92 WA -
testcase_93 WA -
testcase_94 WA -
testcase_95 WA -
testcase_96 WA -
testcase_97 WA -
testcase_98 WA -
testcase_99 WA -
testcase_100 WA -
testcase_101 WA -
testcase_102 WA -
testcase_103 WA -
testcase_104 WA -
testcase_105 WA -
testcase_106 WA -
testcase_107 WA -
testcase_108 WA -
testcase_109 WA -
testcase_110 WA -
testcase_111 WA -
testcase_112 WA -
testcase_113 WA -
testcase_114 WA -
testcase_115 WA -
testcase_116 WA -
testcase_117 WA -
testcase_118 WA -
testcase_119 WA -
testcase_120 WA -
testcase_121 WA -
testcase_122 WA -
testcase_123 WA -
testcase_124 WA -
testcase_125 WA -
testcase_126 WA -
testcase_127 WA -
testcase_128 WA -
testcase_129 WA -
権限があれば一括ダウンロードができます

ソースコード

diff #

import std.conv, std.functional, std.range, std.stdio, std.string;
import std.algorithm, std.array, std.bigint, std.bitmanip, std.complex, std.container, std.math, std.mathspecial, std.numeric, std.regex, std.typecons;
import core.bitop;

class EOFException : Throwable { this() { super("EOF"); } }
string[] tokens;
string readToken() { for (; tokens.empty; ) { if (stdin.eof) { throw new EOFException; } tokens = readln.split; } auto token = tokens.front; tokens.popFront; return token; }
int readInt() { return readToken.to!int; }
long readLong() { return readToken.to!long; }
real readReal() { return readToken.to!real; }

bool chmin(T)(ref T t, in T f) { if (t > f) { t = f; return true; } else { return false; } }
bool chmax(T)(ref T t, in T f) { if (t < f) { t = f; return true; } else { return false; } }

int binarySearch(alias pred, T)(in T[] as) { int lo = -1, hi = cast(int)(as.length); for (; lo + 1 < hi; ) { const mid = (lo + hi) >> 1; (unaryFun!pred(as[mid]) ? hi : lo) = mid; } return hi; }
int lowerBound(T)(in T[] as, T val) { return as.binarySearch!(a => (a >= val)); }
int upperBound(T)(in T[] as, T val) { return as.binarySearch!(a => (a > val)); }


struct ModInt(int M_) {
  import std.conv : to;
  alias M = M_;
  int x;
  this(ModInt a) { x = a.x; }
  this(long a) { x = cast(int)(a % M); if (x < 0) x += M; }
  ref ModInt opAssign(long a) { return (this = ModInt(a)); }
  ref ModInt opOpAssign(string op)(ModInt a) {
    static if (op == "+") { x += a.x; if (x >= M) x -= M; }
    else static if (op == "-") { x -= a.x; if (x < 0) x += M; }
    else static if (op == "*") { x = cast(int)((cast(long)(x) * a.x) % M); }
    else static if (op == "/") { this *= a.inv(); }
    else static assert(false);
    return this;
  }
  ref ModInt opOpAssign(string op)(long a) {
    static if (op == "^^") {
      if (a < 0) return (this = inv()^^(-a));
      ModInt t2 = this, te = ModInt(1);
      for (long e = a; e > 0; e >>= 1) {
        if (e & 1) te *= t2;
        t2 *= t2;
      }
      x = cast(int)(te.x);
      return this;
    } else return mixin("this " ~ op ~ "= ModInt(a)");
  }
  ModInt inv() const {
    int a = x, b = M, y = 1, z = 0, t;
    for (; ; ) {
      t = a / b; a -= t * b;
      if (a == 0) {
        assert(b == 1 || b == -1);
        return ModInt(b * z);
      }
      y -= t * z;
      t = b / a; b -= t * a;
      if (b == 0) {
        assert(a == 1 || a == -1);
        return ModInt(a * y);
      }
      z -= t * y;
    }
  }
  ModInt opUnary(string op: "-")() const { return ModInt(-x); }
  ModInt opBinary(string op, T)(T a) const {
    return mixin("ModInt(this) " ~ op ~ "= a");
  }
  ModInt opBinaryRight(string op)(long a) const {
    return mixin("ModInt(a) " ~ op ~ "= this");
  }
  bool opCast(T: bool)() const { return (x != 0); }
  string toString() const { return x.to!string; }
}

enum MO = 1000000007;
alias Mint = ModInt!MO;


// inv[i] = 1 / i, fac[i] = i!, invFac[i] = 1 / i!
Mint[] inv, fac, invFac;
void prepareFac(int lim) {
  inv = new Mint[lim];
  fac = new Mint[lim];
  invFac = new Mint[lim];
  inv[1] = 1;
  foreach (i; 2 .. lim) {
    inv[i] = -(Mint.M / i) * inv[cast(size_t)(Mint.M % i)];
  }
  fac[0] = invFac[0] = 1;
  foreach (i; 1 .. lim) {
    fac[i] = fac[i - 1] * i;
    invFac[i] = invFac[i - 1] * inv[i];
  }
}

// Find f(n) for the polynomial f s.t. fs = [f(0), f(1), ...] and deg f < |fs|
Mint interpolateIota(const(Mint[]) fs, long n) {
  const fsLen = cast(int)(fs.length);
  auto prodR = new Mint[fsLen + 1];
  prodR[fsLen] = 1;
  foreach_reverse (i; 0 .. fsLen) prodR[i] = (n - i) * prodR[i + 1];
  Mint ans;
  Mint prodL = 1;
  for (int i = 0; i < fsLen; ++i) {
    // (i - 0) ... (i - (i - 1)) (i - (i + 1)) ... (i - (fsLen - 1))
    ans += invFac[i] * (((fsLen - 1 - i) & 1) ? -1 : +1) *
           invFac[fsLen - 1 - i] * fs[i] * prodL * prodR[i + 1];
    prodL *= (n - i);
  }
  return ans;
}

// pws[i] = i^d (0 <= i < n)
Mint[] getMonomials(long d, int n) {
  auto lpf = new int[n];
  foreach (i; 0 .. n) lpf[i] = i;
  foreach (p; 2 .. n) if (lpf[p] == p) {
    for (int i = 2 * p; i < n; i += p) if (lpf[i] > p) lpf[i] = p;
  }
  auto pws = new Mint[n];
  foreach (i; 0 .. n) {
    pws[i] = (lpf[i] == i) ? Mint(i)^^d : (pws[lpf[i]] * pws[i / lpf[i]]);
  }
  return pws;
}

// \sum_{i=0}^{\infty} r^i f(i) (deg f <= d)
Mint sumPowerPolyLimit(Mint r, int d, const(Mint[]) fs) {
  assert(r.x != 1, "sumPowerPolyLimit: r != 1 must hold");
  assert(d + 1 < inv.length, "sumPowerPolyLimit: inv[d + 1] must be prepared");
  assert(d + 1 <= fs.length, "sumPowerPolyLimit: d + 1 < |fs| must hold");
  auto rr = new Mint[d + 1];
  rr[0] = 1;
  foreach (i; 1 .. d + 1) rr[i] = rr[i - 1] * r;
  Mint ans, sumRF;
  foreach (i; 0 .. d + 1) {
    sumRF += rr[i] * fs[i];
    ans += invFac[d - i] * invFac[i + 1] * (((d - i) & 1) ? -1 : +1) *
           rr[d - i] * sumRF;
  }
  ans *= (1 - r)^^(-(d + 1)) * fac[d + 1];
  return ans;
}

// \sum_{i=0}^{\infty} r^i i^d
Mint sumPowerPolyLimit(Mint r, int d) {
  return sumPowerPolyLimit(r, d, getMonomials(d, d + 1));
}

// \sum_{i=0}^{n-1} r^i f(i) (deg f <= d)
Mint sumPowerPoly(Mint r, int d, const(Mint[]) fs, long n) {
writeln("sumPowerPoly ",r," ",d," ",fs," ",n);
  assert(d + 1 < inv.length, "sumPowerPoly: inv[d + 1] must be prepared");
  assert(d + 1 <= fs.length, "sumPowerPoly: d + 1 < |fs| must hold");
  assert(n >= 0, "sumPowerPoly: n >= 0 must hold.");
  if (r.x == 0) return (0 < n) ? fs[0] : Mint(0);
  auto gs = new Mint[d + 2];
  Mint rr = 1;
  gs[0] = 0;
  foreach (i; 0 .. d + 1) {
    gs[i + 1] = gs[i] + rr * fs[i];
    rr *= r;
  }
  if (r.x == 1) return interpolateIota(gs, n);
  const c = sumPowerPolyLimit(r, d, fs);
  const rInv = r.inv();
  Mint rrInv = 1;
  foreach (i; 0 .. d + 2) {
    gs[i] = rrInv * (gs[i] - c);
    rrInv *= rInv;
  }
  return c + r^^n * interpolateIota(gs, n);
}

// \sum_{i=0}^{n-1} r^i i^d
Mint sumPowerPoly(Mint r, int d, long n) {
  return sumPowerPoly(r, d, getMonomials(d, d + 1), n);
}


enum LIM = 505;

// (n - k + 1) (n + 1)^(k-1)
void main() {
  prepareFac(LIM);
  
  auto small = new Mint[LIM];
  foreach (n; 0 .. LIM) {
    small[n] = Mint(n + 1)^^(n - 1) * invFac[n];
  }
  
  try {
    for (; ; ) {
      const N = readLong();
      const M = readInt();
      const S = readToken();
      
      int[] ones;
      if (S[0] == 'o') {
        ones ~= 0;
      }
      for (int i = 0, j; i < M; i = j) {
        for (j = i; j < M && S[i] == S[j]; ++j) {}
        if (S[i] == '-') {
          ones ~= (j - i);
        }
      }
      if (S[M - 1] == 'o') {
        ones ~= 0;
      }
      const onesLen = cast(int)(ones.length);
      debug {
        writeln("ones = ", ones);
      }
      
      int innerSum;
      Mint innerNum = 1;
      alias Query = Tuple!(int[], "as", int, "coef");
      auto qss = new Query[][M + 1];
      if (onesLen == 1) {
        qss[0] ~= Query([0], 1);
        qss[1] ~= Query([0], -M);
        foreach (m; 2 .. M + 1) {
          qss[m] ~= Query([m - 2], M - m + 1);
        }
      } else {
        foreach (a; ones[1 .. onesLen - 1]) {
          innerSum += a;
          innerNum *= small[a];
        }
        foreach (a; 0 .. ones[0] + 1) foreach (b; 0 .. ones[onesLen - 1] + 1) {
          qss[M - (ones[0] - a) - (ones[onesLen - 1] - b)] ~=
              Query([max(a - 1, 0), max(b - 1, 0)], ((a == 0) ? +1 : -1) * ((b == 0) ? +1 : -1));
        }
      }
      debug {
        foreach (m; 0 .. M + 1) {
          writefln("qss[%s] = %s", m, qss[m]);
        }
        void pie(string s, int sig) {
          if (s.length >= 1 && s[0] == '-') {
            pie(s[1 .. $], sig);
            pie('o' ~ s[1 .. $], -sig);
          } else if (s.length >= 1 && s[$ - 1] == '-') {
            pie(s[0 .. $ - 1], sig);
            pie(s[0 .. $ - 1] ~ 'o', -sig);
          } else {
            // writeln("query ", s.length, " ", s, " ", sig);
          }
        }
        pie(S, +1);
      }
      
      Mint ans;
      
      // m = 0
      if (onesLen == 1) {
        ans += Mint(N)^^N * Mint(N + 1);
      }
      
      foreach (m; 1 .. M + 1) {
        auto nums = new Mint[m + 1];
        foreach (ref q; qss[m]) {
          int sum = innerSum;
          Mint num = innerNum;
          foreach (a; q.as) {
            sum += a;
            num *= small[a];
          }
          nums[sum] += q.coef * num;
        }
        debug {
          writefln("m = %s, nums = %s", m, nums);
        }
        
        /*
          0 <= k <= N - m
          (N - m - k + 1) (N - m + 1)^(k-1) / k! * (k + l)! * N^(N - (k + l))
          = (N^(N - l) / (N - m + 1)) * (N - m - k + 1) ((k + l)! / k!) * ((N - m + 1) / N)^k
        */
        foreach (l; 0 .. m + 1) {
          if (nums[l]) {
            auto fs = new Mint[l + 2];
            foreach (k; 0 .. l + 2) {
              fs[k] = (N - m - k + 1) * fac[k + l] * invFac[k];
            }
            const res = sumPowerPoly(Mint(N - m + 1) / Mint(N), l + 1, fs, N - m + 1);
            ans += nums[l] * Mint(N)^^(N - l) / Mint(N - m + 1) * res;
          }
        }
      }
      
      ans *= (N - M + 1);
      writeln(ans);
    }
  } catch (EOFException e) {
  }
}
0