codeforces 1443E-Long Permutation (树状数组 + 康托展开)
题目链接:https://codeforces.com/problemset/problem/1443/E
我们发现,排列的排名最多只会是 \(10^10\),所以最多只会修改 \(15\) 个位置
我们记录一下当前的排列排名是多少,然后只需要暴力进行逆康托展开,求出当前排名下的排列,暴力修改即可
求和用树状数组维护,暴力修改后 \(15\) 个位置即可
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 200010;
int n, q;
ll c[maxn], fac[maxn];
void add(int x, ll k){
for(; x <= n ; x += x & (-x)){
c[x] += k;
}
}
ll query(int x){
ll res = 0;
for(; x ; x -= x & (-x)){
res += c[x];
}
return res;
}
int v[20], a[20], p[maxn];
void change(ll sum){
for(int i = 1 ; i <= 15 ; ++i) v[i] = 1;
ll tmp = sum;
for(int i = 1 ; i <= 15 ; ++i){
int t = tmp / fac[15 - i];
int cnt = 0;
for(int j = 1 ; j <= 15 ; ++j){
if(v[j]){
if(cnt == t){
a[i] = j;
v[j] = 0;
break;
}
++cnt;
}
}
tmp %= fac[15 - i];
}
if(n < 15){
int d = 15 - n;
for(int i = 1 ; i <= n ; ++i){
add(i, -p[i]);
p[i] = a[i + d] - d;
add(i, p[i]);
}
} else{
int d = n - 15;
for(int i = n - 14 ; i <= n ; ++i){
add(i, -p[i]);
p[i] = a[15 - (n - i)] + d;
add(i, p[i]);
}
}
}
ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
int main(){
n = read(), q = read();
for(int i = 1 ; i <= n ; ++i) add(i, i);
for(int i = 1 ; i <= n ; ++i) p[i] = i;
fac[0] = 1;
for(int i = 1 ; i <= 15 ; ++i) fac[i] = fac[i - 1] * i;
ll ans = 0;
int op, x, y;
for(int i = 1 ; i <= q ; ++i){
op = read();
if(op == 1){
x = read(), y = read();
printf("%lld\n", query(y) - query(x - 1));
} else{
x = read();
ans += x;
change(ans);
}
}
return 0;
}