結果
| 問題 | No.3480 Prefix Advantage |
| コンテスト | |
| ユーザー |
37zigen
|
| 提出日時 | 2026-03-20 22:22:56 |
| 言語 | Java (openjdk 25.0.2) |
| 結果 |
AC
|
| 実行時間 | 1,297 ms / 2,000 ms |
| コード長 | 17,771 bytes |
| 記録 | |
| コンパイル時間 | 2,295 ms |
| コンパイル使用メモリ | 106,116 KB |
| 実行使用メモリ | 300,328 KB |
| 最終ジャッジ日時 | 2026-03-20 22:24:06 |
| 合計ジャッジ時間 | 66,833 ms |
|
ジャッジサーバーID (参考情報) |
judge2_0 / judge1_0 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 60 |
ソースコード
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Array;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Queue;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.DoubleUnaryOperator;
import java.util.function.Function;
import java.util.function.IntBinaryOperator;
import java.util.function.IntFunction;
import java.util.function.IntToDoubleFunction;
import java.util.function.IntToLongFunction;
import java.util.function.IntUnaryOperator;
import java.util.function.LongBinaryOperator;
import java.util.function.LongToDoubleFunction;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.ToIntFunction;
import java.util.random.RandomGenerator;
import java.util.stream.IntStream;
import java.util.stream.Stream;
class FastScanner {
private static FastScanner instance = null;
private final InputStream in = System.in;
private final byte[] buffer = new byte[1024];
private int ptr = 0;
private int buflen = 0;
private FastScanner() {
}
public static FastScanner getInstance() {
if (instance == null) {
instance = new FastScanner();
}
return instance;
}
private boolean hasNextByte() {
if (ptr < buflen) {
return true;
}
ptr = 0;
try {
buflen = in.read(buffer);
} catch (IOException e) {
e.printStackTrace();
}
return buflen > 0;
}
private int readByte() {
if (hasNextByte()) {
return buffer[ptr++];
} else {
return -1;
}
}
private boolean isPrintableChar(int c) {
return (33 <= c) && (c <= 126);
}
public boolean hasNext() {
while (hasNextByte() && (!isPrintableChar(buffer[ptr]))) {
ptr++;
}
return hasNextByte();
}
public long nextLong() {
if (!hasNext()) {
throw new NoSuchElementException();
}
long n = 0;
boolean minus = false;
int b = readByte();
if (b == '-') {
minus = true;
b = readByte();
}
while ((b >= '0') && (b <= '9')) {
// n = n * 10 + (b - '0');
n = ((n << 1) + (n << 3)) + (b - '0');
b = readByte();
}
return minus ? -n : n;
}
public int nextInt() {
return ((int) (nextLong()));
}
}
class MergeFiles {}
/**
* 998244353=1119*2^{23}+1は2^23=8388608まで計算可能。
*/
class PolynomialFp {
public static final long mod = 998244353;// 119×2^{23}+1
static Fp mo = new Fp(mod);
static long[][] bitreversedRoots = new long[30][];
static long[][] bitreversedInvRoots = new long[30][];
static long ADD(long a, long b) {
long sum = a + b;
return sum >= mod ? sum - mod : sum;
}
static long SUB(long a, long b) {
return ADD(a, mod - b);
}
static void prepareRoots(int n) {
int sz = Integer.numberOfTrailingZeros(n);
if (bitreversedRoots[sz] != null) {
return;
}
long g = 3;
long root = MathUtils.modPow(g, (mod - 1) / n, mod);
long iroot = MathUtils.modInv(root, mod);
bitreversedRoots[sz] = new long[n];
bitreversedInvRoots[sz] = new long[n];
for (int n_ = n / 2; n_ >= 1; n_ /= 2 , root = (root * root) % mod , iroot = (iroot * iroot) % mod) {
long w = 1;
long iw = 1;
for (int j = 0; j < n_; ++j) {
bitreversedRoots[sz][n_ + j] = w;
bitreversedInvRoots[sz][n_ + j] = iw;
w = (w * root) % mod;
iw = (iw * iroot) % mod;
}
int cur = 0;
for (int j = 0; j < n_; ++j) {
if (cur < j) {
ArrayUtils.swap(n_ + cur, n_ + j, bitreversedRoots[sz]);
ArrayUtils.swap(n_ + cur, n_ + j, bitreversedInvRoots[sz]);
}
for (int k = n_ / 2; k > (cur ^= k); k /= 2);
}
}
}
/**
* fftをbitreversedした順で返す。
* Scott, Michael. "A note on the implementation of the number theoretic transform." IMA International Conference on Cryptography and Coding. Cham: Springer International Publishing, 2017.
*
* @param a
*/
public static void fftTobitReversed(long[] a) {
int n = a.length;
int sz = Integer.numberOfTrailingZeros(a.length);
if (bitreversedRoots[sz] == null) {
prepareRoots(a.length);
}
for (int m = 1, t = n / 2; m <= (n / 2); m *= 2 , t /= 2) {
for (int i = 0, k = 0; i < m; ++i , k += 2 * t) {
long S = bitreversedRoots[sz][m + i];
for (int j = k; j < (k + t); ++j) {
long u = a[j];
long v = (a[j + t] * S) % mod;
a[j] = ADD(u, v);
a[j + t] = SUB(u, v);
}
}
}
}
/**
* Scott, Michael. "A note on the implementation of the number theoretic transform." IMA International Conference on Cryptography and Coding. Cham: Springer International Publishing, 2017.
*
* @param a
*/
public static void ifftFromBitreversed(long[] a) {
long invN = MathUtils.modInv(a.length, mod);
int n = a.length;
int sz = Integer.numberOfTrailingZeros(n);
if (bitreversedInvRoots[sz] == null) {
prepareRoots(a.length);
}
for (int m = n / 2, t = 1; m >= 1; m /= 2 , t *= 2) {
for (int i = 0, k = 0; i < m; ++i , k += 2 * t) {
long S = bitreversedInvRoots[sz][m + i];
if (m == 1) {
S = (S * invN) % mod;
}
for (int j = k; j < (k + t); ++j) {
long u = a[j];
long v = a[j + t];
if (m == 1) {
a[j] = ((u + v) * invN) % mod;
} else {
a[j] = ADD(u, v);
}
a[j + t] = (((u + mod) - v) * S) % mod;
}
}
}
}
static long[] mulFFT(long[] a, long[] b) {
int n = 1;
int len = (a.length + b.length) - 1;
while (n < ((a.length + b.length) - 1)) {
n *= 2;
}
a = Arrays.copyOf(a, n);
b = Arrays.copyOf(b, n);
prepareRoots(n);
fftTobitReversed(a);
fftTobitReversed(b);
for (int i = 0; i < a.length; ++i) {
a[i] = (a[i] * b[i]) % mod;
}
ifftFromBitreversed(a);
return resize(a, len);
}
public static long[] mulNaive(long[] a, long[] b) {
long[] ret = new long[(a.length + b.length) - 1];
for (int i = 0; i < a.length; ++i) {
for (int j = 0; j < b.length; ++j) {
ret[i + j] += a[i] * b[j];
ret[i + j] %= mod;
}
}
return ret;
}
/**
* [-mod+1, mod-1]の範囲外の要素があると、ADD/SUBでバグる。
*
* @param a
* @param b
* @return */
public static long[] mul(long[] a, long[] b) {
for (int i = 0; i < a.length; i++) {
if (a[i] < 0) {
a[i] += mod;
}
}
for (int i = 0; i < b.length; i++) {
if (b[i] < 0) {
b[i] += mod;
}
}
if ((((a.length + b.length) - 1) <= 512) || (Math.min(a.length, b.length) <= 10)) {
return mulNaive(a, b);
} else {
return mulFFT(a, b);
}
}
static long[] resize(long[] a, int len) {
return Arrays.copyOf(a, len);
}
/**
* exp(-x)
* 未テスト
*
* @param n
* @return */
public static long[] invExp(int n) {
long[] iexp = new long[n];
for (int i = 0; i < iexp.length; i++) {
if ((i % 2) == 0) {
iexp[i] = mo.ifac(i);
} else {
iexp[i] = mod - mo.ifac(i);
}
}
return iexp;
}
/**
* exp(x)
* 未テスト
*
* @param n
* @return */
public static long[] exp(int n) {
long[] exp = new long[n];
for (int i = 0; i < exp.length; i++) {
exp[i] = mo.ifac(i);
}
return exp;
}
}
class Zn {
final long mod;
public Zn(long mod) {
this.mod = mod;
}
/**
* *
* 剰余を取り、0以上mod未満の値を返す。
*
* @param a
* @return */
public long reduce(long a) {
a %= mod;
if (a < 0) {
a += mod;
}
return a;
}
}
class ArrayUtils {
public static void swap(int i, int j, long[] A) {
if (i == j) {
return;
}
long tmp = A[i];
A[i] = A[j];
A[j] = tmp;
}
public static void swap(long[] A, long[] B) {
if (A.length != B.length) {
throw new AssertionError();
}
for (int i = 0; i < A.length; i++) {
long tmp = A[i];
A[i] = B[i];
B[i] = tmp;
}
}
}
class MyPrintWriter extends PrintWriter {
private static MyPrintWriter instance = null;
private MyPrintWriter() {
super(System.out);
}
public static MyPrintWriter getInstance() {
if (instance == null) {
instance = new MyPrintWriter();
}
return instance;
}
public void println(boolean[][] a) {
for (int i = 0; i < a.length; i++) {
println(a[i], " ");
}
}
public void println(boolean[] a, String separator) {
for (int i = 0; i < a.length; ++i) {
super.print((a[i] ? 1 : 0) + (i == (a.length - 1) ? "\n" : separator));
}
}
}
class Fp extends Zn {
public Fp(long mod) {
super(mod);
}
long[] fac = new long[0];
long[] ifac = new long[0];
long[] inv = new long[0];
public void expand(int n) {
fac = new long[n];
ifac = new long[n];
inv = new long[n];
Arrays.fill(fac, 1);
Arrays.fill(ifac, 1);
Arrays.fill(inv, 1);
for (int i = 2; i < n; ++i) {
fac[i] = (i * fac[i - 1]) % mod;
inv[i] = mod - (((mod / i) * inv[((int) (mod % i))]) % mod);
ifac[i] = (inv[i] * ifac[i - 1]) % mod;
}
}
public long fac(int n) {
if (fac.length <= n) {
expand(Math.max(2 * fac.length, n + 1));
}
return fac[n];
}
public long ifac(int n) {
if (ifac.length <= n) {
expand(Math.max(2 * ifac.length, n + 1));
}
return ifac[n];
}
public long inv(long n) {
if (n < 0) {
n = reduce(n);
}
return n < inv.length ? inv[((int) (n))] : MathUtils.modInv(n, mod);
}
/**
* comb(n+k-1,k)を返す。n=k=0のときは1を返す。
*
* @param n
* @param k
* @return */
public long combrep(int n, int k) {
if (k < 0) {
return 0;
}
if ((n == 0) && (k == 0)) {
return 1;
}
return comb((n + k) - 1, k);
}
/**
* comb(0, 0)=1とする。
*
* @param n
* @param k
* @return */
public long comb(int n, int k) {
if ((k < 0) || ((n - k) < 0)) {
return 0;
}
return (((fac(n) * ifac(k)) % mod) * ifac(n - k)) % mod;
}
}
class MathUtils {
public static long modPow(long a, long n, long mod) {
if (n < 0) {
long inv = MathUtils.modInv(a, mod);
return MathUtils.modPow(inv, -n, mod);
}
if (n == 0) {
return 1;
}
return (MathUtils.modPow((a * a) % mod, n / 2, mod) * ((n % 2) == 1 ? a : 1)) % mod;
}
/**
* 拡張ユークリッドの互除法で逆元を求める。
*
* @param a
* @param mod
* @return */
public static long modInv(long a, long mod) {
a = ((a % mod) + mod) % mod;
long[] f0 = new long[]{ 1, 0, mod };
long[] f1 = new long[]{ 0, 1, a };
while (f1[2] != 0) {
long q = f0[2] / f1[2];
for (int i = 0; i < 3; i++) {
f0[i] -= q * f1[i];
}
ArrayUtils.swap(f0, f1);
}
return f0[1] < 0 ? mod + f0[1] : f0[1];
}
}
public class Main implements Runnable {
public static void main(String[] args) throws IOException {
Thread.setDefaultUncaughtExceptionHandler((t, e) -> System.exit(1));
// Runtime runtime = Runtime.getRuntime();
// new Thread(null, new Main(), "MainThreadWithLargeStack", (1024 * 1024) * 1024).start();
// new Main().test();
// new Main().gen();
new Main().run();
// long usedMemory = runtime.totalMemory() - runtime.freeMemory();
// System.err.printf("使用メモリ: %.2f MB%n", usedMemory / 1024.0 / 1024.0);
MyPrintWriter.getInstance().flush();
}
@Override
public void run() {
FastScanner sc = FastScanner.getInstance();
MyPrintWriter pw = MyPrintWriter.getInstance();
long mod = 998244353;
int N = sc.nextInt();
int P = sc.nextInt();
int Q = sc.nextInt();
Fp fp = new Fp(mod);
long[] f = new long[N + 1];
for (int n = 1; n <= N; n++) {
f[n] = (fp.combrep(n, P) * fp.combrep(n, Q)) % mod;
f[n] = (f[n] * fp.ifac(n)) % mod;
}
long[] g = PolynomialFp.mul(f, PolynomialFp.invExp(N + 1));
for (int i = 0; i < g.length; i++) {
g[i] = (fp.fac(i) * g[i]) % mod;
g[i] = (g[i] * fp.inv(i)) % mod;
}
for (int i = 0; i < g.length; i++) {
g[i] = (g[i] * fp.ifac(i)) % mod;
}
g = PolynomialFp.mul(PolynomialFp.exp(N + 1), g);
for (int n = 1; n <= N; n++) {
long ans = (g[n] * fp.fac(n)) % mod;
// for (int i = 0; i <= n; i++) {
// ans += fp.comb(n, i)*g[n-i];
// ans %= mod;
// }
pw.println(ans);
}
}
}
// --- Original Code ---
// package template;
//
// import java.io.IOException;
// import java.nio.file.Files;
// import java.nio.file.Path;
// import java.util.Arrays;
// import java.util.List;
// import java.util.Random;
//
// import library.tools.FastScanner;
// import library.tools.MergeFiles;
// import library.tools.MyPrintWriter;
// import library.util.Fp;
// import library.util.polynomial.PolynomialFp;
//
// public class Main implements Runnable {
//
// public static void main(String[] args) throws IOException {
// // Runtime runtime = Runtime.getRuntime();
// // new Thread(null, new Main(), "MainThreadWithLargeStack", (1024 * 1024) * 1024).start();
// // new Main().test();
// // new Main().gen();
// new Main().run();
// // long usedMemory = runtime.totalMemory() - runtime.freeMemory();
// // System.err.printf("使用メモリ: %.2f MB%n", usedMemory / 1024.0 / 1024.0);
// MyPrintWriter.getInstance().flush();
// MergeFiles.export();
// }
//
// @Override
// public void run() {
// FastScanner sc = FastScanner.getInstance();
// MyPrintWriter pw = MyPrintWriter.getInstance();
// long mod=998244353;
// int N=sc.nextInt();
// int P=sc.nextInt();
// int Q=sc.nextInt();
// Fp fp=new Fp(mod);
// long[]f=new long[N+1];
// for (int n = 1; n <= N; n++) {
// f[n]=fp.combrep(n, P)*fp.combrep(n, Q)%mod;
// f[n]=f[n]*fp.ifac(n)%mod;
// }
// long[]g=PolynomialFp.mul(f, PolynomialFp.invExp(N+1));
// for (int i = 0; i < g.length; i++) {
// g[i]=fp.fac(i)*g[i]%mod;
// g[i]=g[i]*fp.inv(i)%mod;
// }
// for (int i = 0; i < g.length; i++) {
// g[i]=g[i]*fp.ifac(i)%mod;
// }
// g=PolynomialFp.mul(PolynomialFp.exp(N+1), g);
// for (int n = 1; n <= N; n++) {
// long ans=g[n]*fp.fac(n)%mod;
// // for (int i = 0; i <= n; i++) {
// // ans += fp.comb(n, i)*g[n-i];
// // ans %= mod;
// // }
// pw.println(ans);
// }
//
//
// }
//
// void abc() {
// Random rnd = new Random();
// try {
// List<String> candidates = Files.readAllLines(Path.of("problems.txt")).stream()
// .filter(line -> !line.contains("o")).map(line -> line.split("\\s+")[0]).toList();
//
// String problem = candidates.get(rnd.nextInt(candidates.size()));
// System.out.println(problem);
//
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
//
// void tr(Object... objects) {
// System.out.println(Arrays.deepToString(objects));
// }
// }
//
37zigen