結果
問題 | No.696 square1001 and Permutation 5 |
ユーザー |
|
提出日時 | 2023-06-25 15:15:04 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 3,435 ms / 10,000 ms |
コード長 | 9,138 bytes |
コンパイル時間 | 3,190 ms |
コンパイル使用メモリ | 224,668 KB |
最終ジャッジ日時 | 2025-02-15 02:13:47 |
ジャッジサーバーID (参考情報) |
judge1 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 2 |
other | AC * 12 |
ソースコード
#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 idreturn count_lower(root, val);}int upper_bound(U val) { // return idreturn 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 intvector<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;}