結果
問題 | No.1204 お菓子配り-FINAL |
ユーザー |
👑 |
提出日時 | 2020-08-30 04:08:27 |
言語 | D (dmd 2.109.1) |
結果 |
AC
|
実行時間 | 2 ms / 8,000 ms |
コード長 | 9,116 bytes |
コンパイル時間 | 2,106 ms |
コンパイル使用メモリ | 162,624 KB |
実行使用メモリ | 6,944 KB |
最終ジャッジ日時 | 2024-06-22 08:39:55 |
合計ジャッジ時間 | 4,331 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge4 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 130 |
ソースコード
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^dMint 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) {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^dMint 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 = 0if (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) {}}