結果
問題 | No.696 square1001 and Permutation 5 |
ユーザー | fumofumofuni |
提出日時 | 2023-06-25 15:15:04 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 3,311 ms / 10,000 ms |
コード長 | 9,138 bytes |
コンパイル時間 | 3,026 ms |
コンパイル使用メモリ | 231,208 KB |
実行使用メモリ | 75,740 KB |
最終ジャッジ日時 | 2024-07-02 13:25:25 |
合計ジャッジ時間 | 18,609 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge1 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 3,291 ms
74,000 KB |
testcase_01 | AC | 3 ms
6,812 KB |
testcase_02 | AC | 4 ms
6,944 KB |
testcase_03 | AC | 8 ms
6,940 KB |
testcase_04 | AC | 14 ms
6,940 KB |
testcase_05 | AC | 29 ms
6,940 KB |
testcase_06 | AC | 77 ms
6,940 KB |
testcase_07 | AC | 180 ms
9,976 KB |
testcase_08 | AC | 492 ms
18,116 KB |
testcase_09 | AC | 1,467 ms
37,064 KB |
testcase_10 | AC | 3,311 ms
75,740 KB |
testcase_11 | AC | 2,438 ms
57,896 KB |
testcase_12 | AC | 2 ms
5,376 KB |
testcase_13 | AC | 2 ms
5,376 KB |
ソースコード
#include<bits/stdc++.h> using namespace std; //#pragma GCC optimize("Ofast") #define rep(i,n) for(ll i=0;i<n;i++) #define repl(i,l,r) for(ll i=(l);i<(r);i++) #define per(i,n) for(ll i=(n)-1;i>=0;i--) #define perl(i,r,l) for(ll i=r-1;i>=l;i--) #define fi first #define se second #define pb push_back #define ins insert #define pqueue(x) priority_queue<x,vector<x>,greater<x>> #define all(x) (x).begin(),(x).end() #define CST(x) cout<<fixed<<setprecision(x) #define vtpl(x,y,z) vector<tuple<x,y,z>> #define rev(x) reverse(x); using ll=long long; using vl=vector<ll>; using vvl=vector<vector<ll>>; using pl=pair<ll,ll>; using vpl=vector<pl>; using vvpl=vector<vpl>; const ll MOD=1000000007; const ll MOD9=998244353; const int inf=1e9+10; const ll INF=4e18; const ll dy[9]={1,0,-1,0,1,1,-1,-1,0}; const ll dx[9]={0,1,0,-1,1,-1,1,-1,0}; template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return true; } return false; } template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return true; } return false; } template<typename U = unsigned, int B = 32> class binary_trie { struct node { int cnt; node *ch[2]; node() : cnt(0), ch{ nullptr, nullptr } {} }; node* add(node* t, U val, int b = B - 1) { if (!t) t = new node; t->cnt += 1; if (b < 0) return t; bool f = (val >> (U)b) & (U)1; t->ch[f] = add(t->ch[f], val, b - 1); return t; } node* sub(node* t, U val, int b = B - 1) { assert(t); t->cnt -= 1; if (t->cnt == 0) return nullptr; if (b < 0) return t; bool f = (val >> (U)b) & (U)1; t->ch[f] = sub(t->ch[f], val, b - 1); return t; } U get_min(node* t, U val, int b = B - 1) const { assert(t); if (b < 0) return 0; bool f = (val >> (U)b) & (U)1; f ^= !t->ch[f]; return get_min(t->ch[f], val, b - 1) | ((U)f << (U)b); } U get(node* t, int k, int b = B - 1) const { if (b < 0) return 0; int m = t->ch[0] ? t->ch[0]->cnt : 0; return k < m ? get(t->ch[0], k, b - 1) : get(t->ch[1], k - m, b - 1) | ((U)1 << (U)b); } int count_lower(node* t, U val, int b = B - 1) { if (!t || b < 0) return 0; bool f = (val >> (U)b) & (U)1; return (f && t->ch[0] ? t->ch[0]->cnt : 0) + count_lower(t->ch[f], val, b - 1); } node *root; public: binary_trie() : root(nullptr) {} int size() const { return root ? root->cnt : 0; } bool empty() const { return !root; } void insert(U val) { root = add(root, val); } void erase(U val) { root = sub(root, val); } U max_element(U bias = 0) const { return get_min(root, ~bias); } U min_element(U bias = 0) const { return get_min(root, bias); } int lower_bound(U val) { // return id return count_lower(root, val); } int upper_bound(U val) { // return id return count_lower(root, val + 1); } U operator[](int k) const { assert(0 <= k && k < size()); return get(root, k); } int count(U val) const { if (!root) return 0; node *t = root; for (int i = B - 1; i >= 0; i--) { t = t->ch[(val >> (U)i) & (U)1]; if (!t) return 0; } return t->cnt; } }; namespace NTT { //MOD9のNTT auto c=NTT::mul(a,b)で受け取り。 std::vector<ll> tmp; size_t sz = 1; inline ll powMod(ll n, ll p, ll m) { ll res = 1; while (p) { if (p & 1) res = res * n % m; n = n * n % m; p >>= 1; } return res; } inline ll invMod(ll n, ll m) { return powMod(n, m - 2, m); } ll extGcd(ll a, ll b, ll &p, ll &q) { if (b == 0) { p = 1; q = 0; return a; } ll d = extGcd(b, a%b, q, p); q -= a/b * p; return d; } pair<ll, ll> ChineseRem(const vector<ll> &b, const vector<ll> &m) { ll r = 0, M = 1; for (int i = 0; i < (int)b.size(); ++i) { ll p, q; ll d = extGcd(M, m[i], p, q); // p is inv of M/d (mod. m[i]/d) if ((b[i] - r) % d != 0) return make_pair(0, -1); ll tmp = (b[i] - r) / d * p % (m[i]/d); r += M * tmp; M *= m[i]/d; } return make_pair((r+M+M)%M, M); } template <ll Mod, ll PrimitiveRoot> struct NTTPart { static std::vector<ll> ntt(std::vector<ll> a, bool inv = false) { size_t mask = sz - 1; size_t p = 0; for (size_t i = sz >> 1; i >= 1; i >>= 1) { auto& cur = (p & 1) ? tmp : a; auto& nex = (p & 1) ? a : tmp; ll e = powMod(PrimitiveRoot, (Mod - 1) / sz * i, Mod); if (inv) e = invMod(e, Mod); ll w = 1; for (size_t j = 0; j < sz; j += i) { for (size_t k = 0; k < i; ++k) { nex[j + k] = (cur[((j << 1) & mask) + k] + w * cur[(((j << 1) + i) & mask) + k]) % Mod; } w = w * e % Mod; } ++p; } if (p & 1) std::swap(a, tmp); if (inv) { ll invSz = invMod(sz, Mod); for (size_t i = 0; i < sz; ++i) a[i] = a[i] * invSz % Mod; } return a; } static std::vector<ll> mul(std::vector<ll> a, std::vector<ll> b) { a = ntt(a); b = ntt(b); for (size_t i = 0; i < sz; ++i) a[i] = a[i] * b[i] % Mod; a = ntt(a, true); return a; } }; std::vector<ll> mul(std::vector<ll> a, std::vector<ll> b) { size_t m = a.size() + b.size() - 1; sz = 1; while (m > sz) sz <<= 1; tmp.resize(sz); a.resize(sz, 0); b.resize(sz, 0); vector<ll> c=NTTPart<998244353,3>::mul(a, b); c.resize(m); return c; } std::vector<ll> mul_ll(std::vector<ll> a, std::vector<ll> b) { size_t m = a.size() + b.size() - 1; sz = 1; while (m > sz) sz <<= 1; tmp.resize(sz); a.resize(sz, 0); b.resize(sz, 0); vector<ll> c=NTTPart<998244353,3>::mul(a, b); vector<ll> d=NTTPart<1224736769,3>::mul(a, b); c.resize(m);d.resize(m); vector<ll> e(m); rep(i,m)e[i]=ChineseRem({c[i],d[i]},{998244353,1224736769}).first; return e; } }; //Big int vector<ll> carry_and_fix(vector<ll> digit) { int N = digit.size(); for(int i = 0; i < N - 1; ++i) { // 繰り上がり処理 (K は繰り上がりの回数) if(digit[i] >= 10) { int K = digit[i] / 10; digit[i] -= K * 10; digit[i + 1] += K; } // 繰り下がり処理 (K は繰り下がりの回数) if(digit[i] < 0) { int K = (-digit[i] - 1) / 10 + 1; digit[i] += K * 10; digit[i + 1] -= K; } } // 一番上の桁が 10 以上なら、桁数を増やすことを繰り返す while(digit.back() >= 10) { int K = digit.back() / 10; digit.back() -= K * 10; digit.push_back(K); } // 1 桁の「0」以外なら、一番上の桁の 0 (リーディング・ゼロ) を消す while(digit.size() >= 2 && digit.back() == 0) { digit.pop_back(); } return digit; } vector<ll> string_to_bigint(string S) { int N = S.size(); // N = (文字列 S の長さ) vector<ll> digit(N); for(int i = 0; i < N; ++i) { digit[i] = S[N - i - 1] - '0'; // 10^i の位の数 } return digit; } string bigint_to_string(vector<ll> digit) { int N = digit.size(); // N = (配列 digit の長さ) string str = ""; for(int i = N - 1; i >= 0; --i) { str += digit[i] + '0'; } return str; } vector<ll> addition(vector<ll> digit_a, vector<ll> digit_b) { int N = max(digit_a.size(), digit_b.size()); // a と b の大きい方 vector<ll> digit_ans(N); // 長さ N の配列 digit_ans を作る for(int i = 0; i < N; ++i) { digit_ans[i] = (i < digit_a.size() ? digit_a[i] : 0) + (i < digit_b.size() ? digit_b[i] : 0); // digit_ans[i] を digit_a[i] + digit_b[i] にする (範囲外の場合は 0) } return carry_and_fix(digit_ans); // 2-4 節「繰り上がり計算」の関数です } vector<ll> multiplication(vector<ll> digit_a, vector<ll> digit_b) { vector<ll> res=NTT::mul(digit_a,digit_b); return carry_and_fix(res); } int main(){ ll n;cin >> n; binary_trie<int,20> bt; rep(i,n)bt.insert(i+1); queue<pair<vl,vl>> que; rep(i,n){ ll a;cin >> a; if(i==n-1)break; ll g=bt.lower_bound(a); ll f=n-i-1;g*=f; // cout << f <<" " << g << endl; auto nf=string_to_bigint(to_string(f)); auto ng=string_to_bigint(to_string(g)); bt.erase(a); que.push({nf,ng}); } while(que.size()>1){ queue<pair<vl,vl>> nque; while(que.size()>=2){ auto x=que.front();que.pop(); auto y=que.front();que.pop(); vl na=multiplication(x.first,y.first); vl nb=addition(multiplication(x.second,y.first),y.second); nque.push({na,nb}); } if(que.size())nque.push(que.front()); swap(que,nque); } auto ans=que.front().second;ans=addition(ans,vl({1})); cout << bigint_to_string(ans) << endl; }