[R67C] 排列

  • 难度 普及
  • 时限 1s
  • 空限 512m
  • 模拟

数据规模:1n,x,y50001 \le n, x, y \le 5000

思路

矩阵第 kk 行是把排列 pp 连续作用 kk 次的结果,即 ak,i=pk(i)a_{k,i}=p^k(i)。由递推 ak,i=ak1,pia_{k,i}=a_{k-1,p_i},可以在已知第 k1k-1 行时用 ak,i=ak1,pia_{k,i}=a_{k-1,p_i} 一次性算出整行。

由于 n,x,yn,x,y 都不超过 50005000,直接从第 11 行逐层模拟到第 max(x,y)\max(x,y) 行即可。在过程中,当层数等于 xx 时把当前行存为 vxvx、等于 yy 时存为 vyvy,最后逐位比较 vxvxvyvy 的字典序输出符号。

空间上只保留「上一层」与「当前层」两个数组(滚动数组),不需要存整个矩阵。

复杂度:时间 O(nmax(x,y))O(n\cdot \max(x,y)),空间 O(n)O(n)

仓颉实现

import std.env.*
import std.convert.*

main(): Int64 {
    let reader = getStdIn()
    let n = Int64.parse(reader.readln().getOrThrow().split(" ", removeEmpty: true)[0])
    let p = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ s => Int64.parse(s) })
    let xy = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ s => Int64.parse(s) })
    let x = xy[0]
    let y = xy[1]
    let nn = n
    var cur = Array<Int64>(nn, { i => p[i] })
    var vx: Array<Int64> = Array<Int64>(nn, { _ => 0 })
    var vy: Array<Int64> = Array<Int64>(nn, { _ => 0 })
    var hi = x
    if (y > hi) {
        hi = y
    }
    if (x == 1) {
        var i = 0
        while (i < nn) {
            vx[i] = cur[i]
            i += 1
        }
    }
    if (y == 1) {
        var i = 0
        while (i < nn) {
            vy[i] = cur[i]
            i += 1
        }
    }
    var k = 2
    while (k <= hi) {
        let prev = cur
        cur = Array<Int64>(nn, { i => prev[p[i] - 1] })
        if (k == x) {
            var i = 0
            while (i < nn) {
                vx[i] = cur[i]
                i += 1
            }
        }
        if (k == y) {
            var i = 0
            while (i < nn) {
                vy[i] = cur[i]
                i += 1
            }
        }
        k += 1
    }
    var i = 0
    var res = "="
    while (i < nn) {
        if (vx[i] < vy[i]) {
            res = "<"
            break
        } else if (vx[i] > vy[i]) {
            res = ">"
            break
        }
        i += 1
    }
    println(res)
    return 0
}

要点:

  • ak,i=ak1,pia_{k,i}=a_{k-1,p_i},由于 pi[1,n]p_i\in[1,n],数组按下标取值时要减 11 转为 00 基下标。
  • 用滚动数组只保留相邻两层,把空间从 O(nmax(x,y))O(n\cdot \max(x,y)) 压到 O(n)O(n)
  • 逐位比较时,第一次遇到不等的元素即可确定大小关系;全部相等则输出 =