結果

問題 No.696 square1001 and Permutation 5
ユーザー fumofumofuni
提出日時 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
権限があれば一括ダウンロードができます

ソースコード

diff #
プレゼンテーションモードにする

#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 {
//MOD9NTT 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;
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
0