cf501D. Misha and Permutations Summation(康托展开)
题意:
给定两个 0~n-1 的排列 a 和 b, 分别表示它们是按字典序第几个排列(0~n!-1)。输出 对应的排列
思路:
先分别康托展开,算出ord,加起来,再逆康托展开变回去。
康托展开长这样:
逆康托展开:
- 首先如果是十进制的ord,要转成变进制:,那么左边第一位是 ,再算
- 不对,上面的做法太傻逼了,像十进制转二进制一样从低位开始溢出就好了!
- 然后线段树搞一下。也可以二分+树状数组(nlognlogn)或者树状数组上倍增(nlogn)
为了练手我全用线段树写了,然而码力太弱居然调了好久
取模要怎么处理?不用都化成十进制老老实实对 n! 取模(这样的话,n阶乘又要对谁取模?),一直在康托变进制上做即可。
写个竖式加法,注意从左到右第 i 位是 n+1-i 进制。溢出就不管了,这就相当于取模
const signed N = 2e5 + 3;
int n, a[N], b[N];
#define alltree 1, 1, n
#define mid ((l+r)>>1)
#define ls u<<1
#define rs u<<1|1
#define lside ls, l, mid
#define rside rs, mid+1, r
int sum[N<<2];
void pushup(int u) {
sum[u] = sum[ls] + sum[rs];
}
void upd(int u, int l, int r, int p) {
if(l == r) return void(sum[u]++);
if(p <= mid) upd(lside, p);
else upd(rside, p);
pushup(u);
}
int askSum(int u, int l, int r, int p) {
if(p == 0) return 0;
if(r <= p) return sum[u];
if(p <= mid) return askSum(lside, p);
else return sum[ls] + askSum(rside, p);
}
int askPos(int u, int l, int r, int x) { //严格前面恰有x个0的位置
if(l == r) return l;
int left0 = mid-l+1 - sum[ls];
//若x==left0,应该去右边找
if(x < left0) return askPos(lside, x);
else return askPos(rside, x-left0);
}
void kangtuo(int a[], int n) { //康托展开
for(int i = 1; i <= n; i++) {
upd(alltree, a[i]); //在a[i]位置+1
a[i] -= askSum(alltree, a[i]-1) + 1; //减去比它小的用过的
}
}
void nikangtuo(int a[], int n) { //逆康托展开
for(int i = 1; i <= n; i++) {
a[i] = askPos(alltree, a[i]); //前面的数中恰有a[i]个0
upd(alltree, a[i]);
}
}
signed main() {
iofast;
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i], a[i]++;
for(int i = 1; i <= n; i++) cin >> b[i], b[i]++;
kangtuo(a, n);
memset(sum, 0, sizeof sum); //线段树清零
kangtuo(b, n);
memset(sum, 0, sizeof sum);
//做加法,从左到右第i位是n+1-i进制
for(int i = n, carry = 0; i; i--) {
a[i] += b[i] + carry;
carry = 0;
if(a[i] >= n+1-i) a[i] -= n+1-i, carry = 1;
}
nikangtuo(a, n);
for(int i = 1; i <= n; i++) cout << a[i] - 1 << ' ';
}
标签:
线段树
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现