結果
| 問題 |
No.1068 #いろいろな色 / Red and Blue and more various colors (Hard)
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2022-03-16 00:01:41 |
| 言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 1,383 ms / 3,500 ms |
| コード長 | 4,354 bytes |
| コンパイル時間 | 1,744 ms |
| コンパイル使用メモリ | 174,940 KB |
| 実行使用メモリ | 20,424 KB |
| 最終ジャッジ日時 | 2024-09-22 16:34:24 |
| 合計ジャッジ時間 | 28,380 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 29 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (decltype(n) i = 0; i < (n); ++i)
#define rep3(i, s, n) for (decltype(n) i = (s); i < (n); ++i)
#define repR(i, n) for (decltype(n) i = (n)-1; i >= 0; --i)
#define rep3R(i, s, n) for (decltype(n) i = (n)-1; i >= (s); --i)
#define repit(it, c) for (auto it = (c).begin(); it != (c).end(); ++it)
#define all(x) ::std::begin(x), ::std::end(x)
using ll = long long;
template <typename T, typename U>
inline bool chmax(T ¤t, const U &test) {
if (current < test) {
current = test;
return true;
}
return false;
}
template <typename T, typename U>
inline bool chmin(T ¤t, const U &test) {
if (current > test) {
current = test;
return true;
}
return false;
}
using ll = long long;
ll INF = 2 * 1e9;
template <typename T>
T pow_mod(T n, T p, T mod) {
T ret = 1;
while (p > 0) {
if (p & 1) {
ret = ret * n % mod;
}
n = n * n % mod;
p >>= 1;
}
return ret;
}
template <typename T>
T ext_gcd(T a, T b, T &x, T &y) {
if (b == 0) {
x = 1, y = 0;
return a;
}
T d = ext_gcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
template <typename T>
T inv_mod(T n, T mod) {
T x(0), y(0);
ext_gcd(n, mod, x, y);
return (x % mod + mod) % mod;
}
template <ll mod, ll primitive_root>
// Fast Modulo Transform
class FMT {
public:
ll get_mod() const { return mod; }
ll get_primitive_root() const { return primitive_root; }
FMT() {}
vector<ll> fmt(vector<ll> a, bool inverse = false) {
ll n = a.size();
assert((n ^ (n & -n)) == 0); // power of 2
int h = 0;
while ((1 << h) < n) {
h++;
}
assert((1 << h) == n); // n == 2^h
// bit reversal
for (int i = 0; i < n; i++) {
int i_rev = 0;
for (int bit = 0; bit < h; bit++) {
i_rev |= ((i >> bit) & 1) << (h - 1 - bit);
}
if (i < i_rev) swap(a[i], a[i_rev]);
}
// 1 の n = 2^e 乗根
ll w = pow_mod(primitive_root, (mod - 1) / n, mod);
assert(pow_mod(w, n, mod) == 1);
if (inverse) {
w = inv_mod(w, mod);
}
// butterfly operation
for (int b = 1; b < n; b *= 2) {
// log_2(b) + 1 段
// ブロックサイズ = 2 * b
ll base = pow_mod(w, n / (2 * b), mod);
ll z = 1;
for (int j = 0; j < b; j++) {
//ブロック内 j 個目
for (int k = 0; k < n; k += 2 * b) {
// k を先頭とするブロック
ll s = a[j + k];
ll t = a[j + k + b] * z % mod;
a[j + k] = (s + t) % mod;
a[j + k + b] = (s - t + mod) % mod;
}
z = z * base % mod;
}
}
if (inverse) {
for (int i = 0; i < n; i++) {
a[i] = a[i] * inv_mod(n, mod) % mod;
}
}
return a;
}
vector<ll> ifmt(vector<ll> a) { return fmt(a, true); }
vector<ll> convolve(vector<ll> a, vector<ll> b) {
ll sz = a.size() + b.size() - 1;
ll n = 1;
while (n < sz) {
n <<= 1;
}
a.resize(n);
b.resize(n);
vector<ll> A = fmt(a);
vector<ll> B = fmt(b);
for (int i = 0; i < n; i++) {
A[i] = A[i] * B[i] % mod;
}
A = ifmt(A);
a.resize(sz);
for (int i = 0; i < sz; i++) {
a[i] = A[i];
}
return a;
}
};
FMT<998244353, 3> fmt;
const ll mod = 998244353;
// 分割統治 FMT
// a: 色 A の配列, 半開区間 [l, r)
vector<ll> rec_convolve(vector<ll> &a, int l, int r) {
if (r - l == 1) {
vector<ll> ret(2);
ret[0] = (a[l] - 1 + mod) % mod; // 色1 以外の場合の数
ret[1] = 1; // 色1 の場合の数
return ret;
}
int sz = r - l + 1; // x^0 から x^sz-1 までの sz 種類の冪
int mid = (l + r) / 2;
vector<ll> v1 = rec_convolve(a, l, mid);
vector<ll> v2 = rec_convolve(a, mid, r);
return fmt.convolve(v1, v2);
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
constexpr char endl = '\n';
///////////////////////////
// input
ll n, q;
cin >> n >> q;
vector<ll> a(n), b(q);
for (auto &e : a) {
cin >> e;
e %= mod;
}
for (auto &e : b) {
cin >> e;
}
// solve
// 形式的冪級数で答えを書くと
// [x^{B_q}] \prod_{i=1}^N ((A_i - 1) + 1 * x)
FMT<998244353, 3> fmt;
vector<ll> v = rec_convolve(a, 0, n);
// output
rep(i, q) { cout << v[b[i]] << endl; }
}