結果

問題 No.1204 お菓子配り-FINAL
ユーザー 👑 hos.lyric
提出日時 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
権限があれば一括ダウンロードができます

ソースコード

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) {
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) {
}
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
0