QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#222858 | #5047. Permutation | absinthe | TL | 0ms | 0kb | C++23 | 5.6kb | 2023-10-21 19:17:08 | 2023-10-21 19:17:09 |
answer
// problem-url: https://qoj.ac/contest/1039/problem/5047
#if not LOCAL
#define NDEBUG 1
#endif
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(auto i = a; i < (b); ++i)
#define down(x, a) for (auto x = a; x--;)
#define all(x) begin(x), end(x)
#define sz(x) int(size(x))
#define let auto const
using ll = long long;
using lint = ll;
using pii = pair<int, int>;
using vi = vector<int>;
let mod=998244353;
// { ==== Begin library /home/user202729/icpc-trd/content/number-theory/ModularArithmetic.h ====
/**
* Author: user202729
* Date: 2023-10-09
* License: CC0
* Source: folklore
* Status: not tested very well
* Description: Operators for modular arithmetic. You need to set {\tt mod} to
* some number first and then you can use the structure.
*/
// { ==== Begin library euclid.h ====
/**
* Author: Unknown
* Date: 2002-09-15
* Source: predates tinyKACTL
* Description: Finds two integers $x$ and $y$, such that $ax+by=\gcd(a,b)$. If
* you just need gcd, use the built in \texttt{\_\_gcd} instead.
* If $a$ and $b$ are coprime, then $x$ is the inverse of $a \pmod{b}$.
*/
ll euclid(ll a, ll b, ll &x, ll &y) {
if (!b) return x = 1, y = 0, a;
ll d = euclid(b, a % b, y, x);
return y -= a/b * x, d;
}
// } ==== End library euclid.h ====
struct Mod {
int x;
Mod(int y=0) : x(y%mod) { if(x<0) x+=mod; }
static Mod raw(int y){ Mod r; r.x=y; return r; }
void operator+=(Mod b) { if((x+=b.x)>=mod) x-=mod; }
void operator-=(Mod b) { if((x-=b.x)<0) x+=mod; }
Mod operator-() const { return 0-*this; }
void operator*=(Mod b) { x=int(ll(x) * b.x % mod); }
explicit operator int() const{return x;}
[[nodiscard]] Mod pow(auto p) const {
assert(p>=0);
Mod a=*this;
Mod ans = 1; for (; p; p >>= 1, a *= a) if (p&1) ans *= a;
return ans;
}
[[nodiscard]] Mod inv() const {
assert(x!=0);
return pow(mod-2);
//ll z, y, g = euclid(mod, x, z, y); assert(g == 1); return int(y);
}
void operator/=(Mod b) { *this *= b.inv(); }
#define A(O) [[nodiscard]] friend Mod operator O(Mod a, Mod b) { a O##= b; return a; }
A(+) A(-) A(*) A(/)
#undef A
#define C(O) [[nodiscard]] bool operator O(Mod b) const { return x O b.x; }
C(==) C(!=) C(<) C(>) C(<=) C(>=)
#undef C
};
// } ==== End library /home/user202729/icpc-trd/content/number-theory/ModularArithmetic.h ====
// { ==== Begin library YComb ====
template<class T> struct YComb_{
T f;
template<class... Args> auto operator()(Args&&... args)const{
return f(*this, std::forward<Args>(args)...);
}
};
template<class T> YComb_<T> YComb(T f){ return {std::move(f)}; }
// } ==== End library YComb ====
#define brute 1
int main() {
cin.tie(0)->sync_with_stdio(0);
cin.exceptions(cin.failbit);
#if brute
rep(seed, 831, 1000000007){
mt19937 engine(seed);
let n=uniform_int_distribution(2, 9)(engine);
let c=uniform_int_distribution(2, 10)(engine);
#else
int t; cin>>t;
down(_, t){
int n; cin>>n;
int c; cin>>c;
#endif
vector<int> pos(n, -1);
#if LOCAL
vector<int> permutation(n);
#endif
rep(i, 0, n){
int val;
#if brute
do val=uniform_int_distribution(0, n-1)(engine); while(pos[val]>=0);
#else
cin>>val; --val;
#endif
pos[val]=i;
#if LOCAL
permutation[i]=val;
#endif
}
struct Block{
int rightEnd, leftExtent, leftVal, rightExtent, rightVal;
};
map<int, Block> ranges;
ranges.insert({0, {n, 0, -1, n, -1}});
vector<int> par(n, -1);
vector<int> len(n);
rep(val, 0, n){
let p=pos[val];
let iter=--ranges.upper_bound(p);
auto& [leftEnd, block]=*iter;
auto& [rightEnd, leftExtent, leftVal, rightExtent, rightVal]=block;
assert(p<rightEnd);
assert(leftEnd<=leftExtent);
assert(leftExtent<=rightExtent);
assert(rightExtent<=rightEnd);
int left=p, right=p+1;
down(_, 2){
if(leftExtent!=0 and left-leftExtent<c and leftEnd+(leftEnd==0)+c<=rightEnd) left=leftEnd, right=max(right, min(rightEnd, leftExtent+c));
if(rightExtent!=n and rightExtent-right<c and rightEnd-(rightEnd==n)-c>=leftEnd) right=rightEnd, left=min(left, max(leftEnd, rightExtent-c));
}
if(left==leftEnd and right-left>1){
assert(right>=leftExtent);
if(leftVal>=0) par[leftVal]=val;
leftVal=val, leftExtent=right;
if(right==rightEnd){
if(rightVal>=0) par[rightVal]=val;
rightVal=-1, rightExtent=rightEnd;
}
}else if(right==rightEnd and right-left>1){
assert(left<=rightExtent);
if(rightVal>=0) par[rightVal]=val;
rightVal=val, rightExtent=left;
assert(left!=leftEnd);
}else{
let oldRightEnd=rightEnd, oldRightExtent=rightExtent, oldRightVal=rightVal;
rightExtent=rightEnd=p;
rightVal=-1;
ranges.insert(iter, {p+1, {oldRightEnd, p+1, -1, oldRightExtent, oldRightVal}});
}
len[val]=right-left;
//assert(cerr<<val<<":"<<left<<' '<<right<<'\n');
}
vector<int> used(n);
Mod answer=1;
rep(val, 0, n){
answer*=len[val]-used[val];
if(par[val]>=0) used[par[val]]+=used[val]+1;
}
#if LOCAL
set<vector<int>> reachable;
YComb([&](auto dfs, vector<int> permutation)->void{
auto [iterator, inserted]=reachable.insert(permutation);
if(inserted){
rep(i, 0, n-c){
auto iter=min_element(permutation.begin()+i, permutation.begin()+i+c+1);
if(iter==permutation.begin()+i){
auto copy=permutation;
sort(copy.begin()+i+1, copy.begin()+i+c+1);
do{
dfs(copy);
}while(next_permutation(copy.begin()+i+1, copy.begin()+i+c+1));
}
if(iter==permutation.begin()+i+c){
auto copy=permutation;
sort(copy.begin()+i, copy.begin()+i+c);
do{
dfs(copy);
}while(next_permutation(copy.begin()+i, copy.begin()+i+c));
}
}
}
})(permutation);
assert(answer==Mod(sz(reachable)));
#endif
cout<<int(answer)<<'\n';
}
}
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 0
Time Limit Exceeded
input:
5 5 3 3 4 2 1 5 5 4 4 2 1 3 5 5 2 4 5 3 1 2 5 3 4 3 2 1 5 5 2 2 3 1 5 4
output:
24 48 480 1 1 1 324 1 1 6 1 24 1 72 1 1 1 6 96 1 1 1 1 1 1 1 1 1 1 1 1 1 5040 1 1 1 1 1 1 1 1 1 1 35280 1 24 1 1 1 1 1 36 1 1 1 1 1 1 1 120 2 600 1 4320 24 18 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 108 1 12 360 1 1 1 4 1 1 4 1 1 1 48 1 24 1 1 1 1 1 1 1 1 1 35280 1 24 1 480 48 1 120 1 1 1 1 96 1 1 1 1 2 120...