提出 #17072303
ソースコード 拡げる
#include <bits/stdc++.h>
using namespace std;
template<typename T>
struct Z_p{
using Type = typename decay<decltype(T::value)>::type;
static vector<Type> mod_inv;
constexpr Z_p(): value(){ }
template<typename U> Z_p(const U &x){ value = normalize(x); }
template<typename U> static Type normalize(const U &x){
Type v;
if(-mod() <= x && x < mod()) v = static_cast<Type>(x);
else v = static_cast<Type>(x % mod());
if(v < 0) v += mod();
return v;
}
const Type& operator()() const{ return value; }
template<typename U> explicit operator U() const{ return static_cast<U>(value); }
constexpr static Type mod(){ return T::value; }
Z_p &operator+=(const Z_p &otr){ if((value += otr.value) >= mod()) value -= mod(); return *this; }
Z_p &operator-=(const Z_p &otr){ if((value -= otr.value) < 0) value += mod(); return *this; }
template<typename U> Z_p &operator+=(const U &otr){ return *this += Z_p(otr); }
template<typename U> Z_p &operator-=(const U &otr){ return *this -= Z_p(otr); }
Z_p &operator++(){ return *this += 1; }
Z_p &operator--(){ return *this -= 1; }
Z_p operator++(int){ Z_p result(*this); *this += 1; return result; }
Z_p operator--(int){ Z_p result(*this); *this -= 1; return result; }
Z_p operator-() const{ return Z_p(-value); }
template<typename U = T>
typename enable_if<is_same<typename Z_p<U>::Type, int>::value, Z_p>::type &operator*=(const Z_p& rhs){
#ifdef _WIN32
uint64_t x = static_cast<int64_t>(value) * static_cast<int64_t>(rhs.value);
uint32_t xh = static_cast<uint32_t>(x >> 32), xl = static_cast<uint32_t>(x), d, m;
asm(
"divl %4; \n\t"
: "=a" (d), "=d" (m)
: "d" (xh), "a" (xl), "r" (mod())
);
value = m;
#else
value = normalize(static_cast<int64_t>(value) * static_cast<int64_t>(rhs.value));
#endif
return *this;
}
template<typename U = T>
typename enable_if<is_same<typename Z_p<U>::Type, int64_t>::value, Z_p>::type &operator*=(const Z_p &rhs){
int64_t q = static_cast<int64_t>(static_cast<long double>(value) * rhs.value / mod());
value = normalize(value * rhs.value - q * mod());
return *this;
}
template<typename U = T>
typename enable_if<!is_integral<typename Z_p<U>::Type>::value, Z_p>::type &operator*=(const Z_p &rhs){
value = normalize(value * rhs.value);
return *this;
}
Z_p operator^(long long e) const{
Z_p b = *this, res = 1;
if(e < 0) b = 1 / b, e = -e;
for(; e; b *= b, e >>= 1) if(e & 1) res *= b;
return res;
}
Z_p &operator^=(const long long &e){ return *this = *this ^ e; }
Z_p &operator/=(const Z_p &otr){
Type a = otr.value, m = mod(), u = 0, v = 1;
if(a < int(mod_inv.size())) return *this *= mod_inv[a];
while(a){
Type t = m / a;
m -= t * a; swap(a, m);
u -= t * v; swap(u, v);
}
assert(m == 1);
return *this *= u;
}
template<typename U> friend const Z_p<U> &abs(const Z_p<U> &v){ return v; }
template<typename U> friend bool operator==(const Z_p<U> &lhs, const Z_p<U> &rhs);
template<typename U> friend bool operator<(const Z_p<U> &lhs, const Z_p<U> &rhs);
template<typename U> friend istream &operator>>(istream &in, Z_p<U> &number);
Type value;
};
template<typename T> bool operator==(const Z_p<T> &lhs, const Z_p<T> &rhs){ return lhs.value == rhs.value; }
template<typename T, typename U, typename enable_if<is_integral<U>::value>::type* = nullptr> bool operator==(const Z_p<T>& lhs, U rhs){ return lhs == Z_p<T>(rhs); }
template<typename T, typename U, typename enable_if<is_integral<U>::value>::type* = nullptr> bool operator==(U lhs, const Z_p<T> &rhs){ return Z_p<T>(lhs) == rhs; }
template<typename T> bool operator!=(const Z_p<T> &lhs, const Z_p<T> &rhs){ return !(lhs == rhs); }
template<typename T, typename U, typename enable_if<is_integral<U>::value>::type* = nullptr> bool operator!=(const Z_p<T> &lhs, U rhs){ return !(lhs == rhs); }
template<typename T, typename U, typename enable_if<is_integral<U>::value>::type* = nullptr> bool operator!=(U lhs, const Z_p<T> &rhs){ return !(lhs == rhs); }
template<typename T> bool operator<(const Z_p<T> &lhs, const Z_p<T> &rhs){ return lhs.value < rhs.value; }
template<typename T> Z_p<T> operator+(const Z_p<T> &lhs, const Z_p<T> &rhs){ return Z_p<T>(lhs) += rhs; }
template<typename T, typename U, typename enable_if<is_integral<U>::value>::type* = nullptr> Z_p<T> operator+(const Z_p<T> &lhs, U rhs){ return Z_p<T>(lhs) += rhs; }
template<typename T, typename U, typename enable_if<is_integral<U>::value>::type* = nullptr> Z_p<T> operator+(U lhs, const Z_p<T> &rhs){ return Z_p<T>(lhs) += rhs; }
template<typename T> Z_p<T> operator-(const Z_p<T> &lhs, const Z_p<T> &rhs){ return Z_p<T>(lhs) -= rhs; }
template<typename T, typename U, typename enable_if<is_integral<U>::value>::type* = nullptr> Z_p<T> operator-(const Z_p<T>& lhs, U rhs){ return Z_p<T>(lhs) -= rhs; }
template<typename T, typename U, typename enable_if<is_integral<U>::value>::type* = nullptr> Z_p<T> operator-(U lhs, const Z_p<T> &rhs){ return Z_p<T>(lhs) -= rhs; }
template<typename T> Z_p<T> operator*(const Z_p<T> &lhs, const Z_p<T> &rhs){ return Z_p<T>(lhs) *= rhs; }
template<typename T, typename U, typename enable_if<is_integral<U>::value>::type* = nullptr> Z_p<T> operator*(const Z_p<T>& lhs, U rhs){ return Z_p<T>(lhs) *= rhs; }
template<typename T, typename U, typename enable_if<is_integral<U>::value>::type* = nullptr> Z_p<T> operator*(U lhs, const Z_p<T> &rhs){ return Z_p<T>(lhs) *= rhs; }
template<typename T> Z_p<T> operator/(const Z_p<T> &lhs, const Z_p<T> &rhs) { return Z_p<T>(lhs) /= rhs; }
template<typename T, typename U, typename enable_if<is_integral<U>::value>::type* = nullptr> Z_p<T> operator/(const Z_p<T>& lhs, U rhs) { return Z_p<T>(lhs) /= rhs; }
template<typename T, typename U, typename enable_if<is_integral<U>::value>::type* = nullptr> Z_p<T> operator/(U lhs, const Z_p<T> &rhs) { return Z_p<T>(lhs) /= rhs; }
template<typename T> istream &operator>>(istream &in, Z_p<T> &number){
typename common_type<typename Z_p<T>::Type, int64_t>::type x;
in >> x;
number.value = Z_p<T>::normalize(x);
return in;
}
template<typename T> ostream &operator<<(ostream &out, const Z_p<T> &number){ return out << number(); }
/*
using ModType = int;
struct VarMod{ static ModType value; };
ModType VarMod::value;
ModType &mod = VarMod::value;
using Zp = Z_p<VarMod>;
*/
constexpr int mod = (119 << 23) + 1;
using Zp = Z_p<integral_constant<decay<decltype(mod)>::type, mod>>;
template<typename T> vector<typename Z_p<T>::Type> Z_p<T>::mod_inv;
template<typename T = integral_constant<decay<decltype(mod)>::type, mod>>
void precalc_inverse(size_t SZ){
auto &inv = Z_p<T>::mod_inv;
if(inv.empty()) inv.assign(2, 1);
for(; inv.size() <= SZ; ) inv.push_back((mod - 1LL * mod / int(inv.size()) * inv[mod % int(inv.size())] % mod) % mod);
}
// Requires Z_p
template<int SZ, typename T = Zp>
struct combinatorics{
vector<T> inv, fact, invfact;
vector<vector<T>> stir1, stir2;
combinatorics(): inv(SZ << 1 | 1, 1), fact(SZ << 1 | 1, 1), invfact(SZ << 1 | 1, 1){
for(int i = 1; i <= SZ << 1; ++ i) fact[i] = fact[i - 1] * i;
invfact[SZ << 1] = 1 / fact[SZ << 1];
for(int i = (SZ << 1) - 1; i >= 0; -- i){
invfact[i] = invfact[i + 1] * (i + 1);
inv[i + 1] = invfact[i + 1] * fact[i];
}
} // O(SZ)
T C(int n, int k){ return n < k ? 0 : fact[n] * invfact[k] * invfact[n - k]; }
T P(int n, int k){ return n < k ? 0 : fact[n] * invfact[n - k]; }
T H(int n, int k){ return C(n + k - 1, k); }
vector<T> precalc_power(int base, int n = SZ << 1){
vector<T> res(n + 1, 1);
for(int i = 1; i <= n; ++ i) res[i] = res[i - 1] * base;
return res;
}
T naive_C(long long n, long long k){
if(n < k) return 0;
T res = 1;
k = min(k, n - k);
for(long long i = n; i > n - k; -- i) res *= i;
return res * invfact[k];
}
T naive_P(long long n, int k){
if(n < k) return 0;
T res = 1;
for(long long i = n; i > n - k; -- i) res *= i;
return res;
}
T naive_H(long long n, long long k){ return naive_C(n + k - 1, k); }
bool parity_C(long long n, long long k){ return n < k ? 0 : k & n - k ^ 1; }
// Catalan's Trapzoids
// # of bitstrings of n Xs and k Ys such that in each initial segment, (# of X) + m > (# of Y)
T Cat(int n, int k, int m = 1){
if(m <= 0) return 0;
else if(k >= 0 && k < m) return C(n + k, k);
else if(k < n + m) return C(n + k, k) - C(n + k, k - m);
else return 0;
}
// Stirling number
// First kind (unsigned): # of n-permutations with k disjoint cycles
// Also the coefficient of x^k for x_n = x(x+1)...(x+n-1)
// Second kind: # of ways to partition a set of size n into r non-empty sets
// Satisfies sum{k=0~n}(x_k) = x^n
array<bool, 2> pre{};
template<bool FIRST = true>
void precalc_stir(int n, int k){
auto &s = FIRST ? stir1 : stir2;
pre[!FIRST] = true;
s.resize(n + 1, vector<T>(k + 1, 1));
for(int i = 1; i <= n; ++ i) for(int j = 1; j <= k; ++ j){
s[i][j] = (FIRST ? i - 1 : j) * s[i - 1][j] + s[i - 1][j - 1];
}
}
// unsigned
T Stir1(int n, int k){
if(n < k) return 0;
assert(pre[0]);
return stir1[n][k];
}
T Stir2(long long n, int k){
if(n < k) return 0;
if(pre[1] && n < int(stir2.size())) return stir2[n][k];
T res = 0;
for(int i = 0, sign = 1; i <= k; ++ i, sign *= -1) res += sign * C(k, i) * (Zp(k - i) ^ n);
return res * invfact[k];
}
bool parity_Stir2(long long n, long long k){ return n < k ? 0 : k ? !(n - k & k - 1 >> 1) : 0; }
};
// Requires modular
template<int root = 15311432, int root_pw = 1 << 23, int inv_root = 469870224, typename IT = vector<Zp>::iterator>
void number_theoric_transform(IT begin, IT end, const bool invert = false){
int n = end - begin;
for(int i = 1, j = 0; i < n; ++ i){
int bit = n >> 1;
for(; j & bit; bit >>= 1) j ^= bit;
j ^= bit;
if(i < j) swap(*(begin + i), *(begin + j));
}
for(int len = 1; len < n; len <<= 1){
typename iterator_traits<IT>::value_type wlen = invert ? inv_root : root;
for(int i = len << 1; i < root_pw; i <<= 1) wlen *= wlen;
for(int i = 0; i < n; i += len << 1){
typename iterator_traits<IT>::value_type w = 1;
for(int j = 0; j < len; ++ j){
auto u = *(begin + i + j), v = *(begin + i + j + len) * w;
*(begin + i + j) = u + v;
*(begin + i + j + len) = u - v;
w *= wlen;
}
}
}
if(invert){
auto inv_n = typename iterator_traits<IT>::value_type(1) / n;
for(auto it = begin; it != end; ++ it) *it *= inv_n;
}
}
const size_t magic_constant = 250;
template<typename Poly>
void convolute(Poly &a, Poly b){
if(min(a.size(), b.size()) < magic_constant){
Poly res((int)a.size() + (int)b.size() - 1);
for(size_t i = 0; i < a.size(); ++ i) for(size_t j = 0; j < b.size(); ++ j) res[i + j] += a[i] * b[j];
a = move(res);
return;
}
int n = max((int)a.size() + (int)b.size() - 1, 1);
if(__builtin_popcount(n) != 1) n = 1 << __lg(n) + 1;
a.resize(n), b.resize(n);
number_theoric_transform(a.begin(), a.end()), number_theoric_transform(b.begin(), b.end());
for(int i = 0; i < n; ++ i) a[i] *= b[i];
number_theoric_transform(a.begin(), a.end(), 1);
while(!a.empty() && !a.back()) a.pop_back();
}
// DEBUG BEGIN
#ifdef LOCAL
template<typename L, typename R> ostream &operator<<(ostream &out, const pair<L, R> &p){
return out << "(" << p.first << ", " << p.second << ")";
}
template<typename Tuple, size_t N> struct TuplePrinter{
static ostream &print(ostream &out, const Tuple &t){ return TuplePrinter<Tuple, N-1>::print(out, t) << ", " << get<N-1>(t); }
};
template<typename Tuple> struct TuplePrinter<Tuple, 1>{
static ostream &print(ostream &out, const Tuple& t){ return out << get<0>(t); }
};
template<typename... Args> ostream &print_tuple(ostream &out, const tuple<Args...> &t){
return TuplePrinter<decltype(t), sizeof...(Args)>::print(out << "(", t) << ")";
}
template<typename ...Args> ostream &operator<<(ostream &out, const tuple<Args...> &t){
return print_tuple(out, t);
}
template<typename T> ostream &operator<<(enable_if_t<!is_same<T, string>::value, ostream> &out, const T &arr){
out << "{"; for(auto &x: arr) out << x << ", ";
return out << (arr.size() ? "\b\b" : "") << "}";
}
template<size_t S> ostream &operator<<(ostream &out, const bitset<S> &b){
for(int i = 0; i < S; ++ i) out << b[i];
return out;
}
void debug_out(){ cerr << "\b\b " << endl; }
template<typename Head, typename... Tail>
void debug_out(Head H, Tail... T){ cerr << H << ", ", debug_out(T...); }
void debug2_out(){ cerr << "-----DEBUG END-----\n"; }
template<typename Head, typename... Tail>
void debug2_out(Head H, Tail... T){ cerr << "\n"; for(auto x: H) cerr << x << "\n"; debug2_out(T...); }
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__)
#define debug2(...) cerr << "----DEBUG BEGIN----\n[" << #__VA_ARGS__ << "]:", debug2_out(__VA_ARGS__)
#else
#define debug(...) 42
#define debug2(...) 42
#endif
// DEBUG END
int main(){
cin.tie(0)->sync_with_stdio(0);
cin.exceptions(ios::badbit | ios::failbit);
combinatorics<100000> C;
auto invp = C.precalc_power((Zp(1) / 2).value);
int n;
cin >> n;
const int mx = 1e5;
vector<int> cnt(mx);
for(auto i = 0; i < 2 * n; ++ i){
int x;
cin >> x, -- x;
++ cnt[x];
}
auto calc = [&](int tot, int sub){
assert(2 * sub <= tot);
return C.fact[tot] * C.invfact[sub] * invp[sub] * C.invfact[tot - 2 * sub];
};
vector<vector<Zp>> poly(mx);
priority_queue<array<int, 2>, vector<array<int, 2>>, greater<>> pq;
for(auto i = 0; i < mx; ++ i){
if(cnt[i] > 1){
for(auto x = 0; x <= cnt[i] / 2; ++ x){
poly[i].push_back(calc(cnt[i], x));
}
pq.push({(int)poly.size(), i});
}
}
if(pq.empty()){
cout << calc(2 * n, n) << "\n";
return 0;
}
while((int)pq.size() > 1){
int i = pq.top()[1]; pq.pop();
int j = pq.top()[1]; pq.pop();
debug(i, j);
convolute(poly[i], poly[j]);
debug((int)poly[i].size(), i);
pq.push({(int)poly[i].size(), i});
}
int i = pq.top()[1];
Zp res = 0;
for(auto j = 0, sign = 1; j < (int)poly[i].size(); ++ j, sign = -sign){
res += sign * calc(2 * n - 2 * j, n - j) * poly[i][j];
}
cout << res << "\n";
return 0;
}
/*
*/
////////////////////////////////////////////////////////////////////////////////////////
// //
// Coded by Aeren //
// //
////////////////////////////////////////////////////////////////////////////////////////
提出情報
コンパイルエラー
./Main.cpp: In function ‘int main()’:
./Main.cpp:281:20: warning: statement has no effect [-Wunused-value]
281 | #define debug(...) 42
| ^~
./Main.cpp:321:3: note: in expansion of macro ‘debug’
321 | debug(i, j);
| ^~~~~
./Main.cpp:281:20: warning: statement has no effect [-Wunused-value]
281 | #define debug(...) 42
| ^~
./Main.cpp:323:3: note: in expansion of macro ‘debug’
323 | debug((int)poly[i].size(), i);
| ^~~~~
./Main.cpp: In instantiation of ‘void convolute(Poly&, Poly) [with Poly = std::vector<Z_p<std::integral_constant<int, 998244353> > >]’:
./Main.cpp:322:29: required from here
./Main.cpp:239:50: warning: suggest parentheses around ‘+’ inside ‘<<’ [-Wparentheses]
239 | if(__builtin_popcount(n) != 1) n = 1 << __lg(n) + 1;
| ~~~~~~~~^~~
ジャッジ結果
| セット名 |
Sample |
All |
| 得点 / 配点 |
0 / 0 |
0 / 600 |
| 結果 |
|
|
| セット名 |
テストケース |
| Sample |
example0.txt, example1.txt |
| All |
000.txt, 001.txt, 002.txt, 003.txt, 004.txt, 005.txt, 006.txt, 007.txt, 008.txt, 009.txt, 010.txt, 011.txt, 012.txt, 013.txt, 014.txt, 015.txt, 016.txt, 017.txt, 018.txt, 019.txt, 020.txt, example0.txt, example1.txt |
| ケース名 |
結果 |
実行時間 |
メモリ |
| 000.txt |
AC |
23 ms |
9016 KiB |
| 001.txt |
AC |
20 ms |
9376 KiB |
| 002.txt |
AC |
36 ms |
9768 KiB |
| 003.txt |
AC |
35 ms |
9660 KiB |
| 004.txt |
AC |
50 ms |
9636 KiB |
| 005.txt |
AC |
42 ms |
9796 KiB |
| 006.txt |
AC |
54 ms |
9792 KiB |
| 007.txt |
AC |
62 ms |
9928 KiB |
| 008.txt |
AC |
70 ms |
10008 KiB |
| 009.txt |
AC |
112 ms |
9868 KiB |
| 010.txt |
AC |
143 ms |
9824 KiB |
| 011.txt |
AC |
276 ms |
9876 KiB |
| 012.txt |
AC |
480 ms |
10128 KiB |
| 013.txt |
AC |
955 ms |
10016 KiB |
| 014.txt |
TLE |
2179 ms |
10180 KiB |
| 015.txt |
TLE |
2205 ms |
10124 KiB |
| 016.txt |
TLE |
2205 ms |
10116 KiB |
| 017.txt |
TLE |
2205 ms |
9928 KiB |
| 018.txt |
TLE |
2205 ms |
10280 KiB |
| 019.txt |
TLE |
2205 ms |
10148 KiB |
| 020.txt |
TLE |
2206 ms |
10524 KiB |
| example0.txt |
AC |
15 ms |
8896 KiB |
| example1.txt |
AC |
14 ms |
8796 KiB |