結果
| 問題 |
No.1340 おーじ君をさがせ
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2023-06-04 22:01:58 |
| 言語 | TypeScript (5.7.2) |
| 結果 |
AC
|
| 実行時間 | 168 ms / 2,000 ms |
| コード長 | 12,280 bytes |
| コンパイル時間 | 8,163 ms |
| コンパイル使用メモリ | 231,844 KB |
| 実行使用メモリ | 49,288 KB |
| 最終ジャッジ日時 | 2024-12-31 16:50:01 |
| 合計ジャッジ時間 | 15,552 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge1 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 59 |
ソースコード
import * as fs from 'fs'
import { resolve } from 'path'
/**
* 位集,用于存储大量的布尔值,可以有效地节省内存.
*/
class BitSet {
static from(arrayLike: ArrayLike<number | string>): BitSet {
const bitSet = new BitSet(arrayLike.length)
for (let i = 0; i < arrayLike.length; i++) {
if (Number(arrayLike[i]) === 1) {
bitSet.add(i)
}
}
return bitSet
}
// lowbit.bit_length() - 1
private static _trailingZeros32(uint32: number): number {
if (uint32 === 0) return 32
return 31 - Math.clz32(uint32 & -uint32) // bitLength32(uint32 & -uint32) - 1
}
private static _onesCount32(uint32: number): number {
uint32 -= (uint32 >>> 1) & 0x55555555
uint32 = (uint32 & 0x33333333) + ((uint32 >>> 2) & 0x33333333)
return (((uint32 + (uint32 >>> 4)) & 0x0f0f0f0f) * 0x01010101) >>> 24
}
private static _bitLength32(uint32: number): number {
return 32 - Math.clz32(uint32)
}
private readonly _bits: Uint32Array
private readonly _n: number
constructor(n: number) {
this._bits = new Uint32Array((n >> 5) + 1)
this._n = n
}
add(i: number): void {
this._bits[i >> 5] |= 1 << (i & 31)
}
/**
* [start, end) 范围内的位置为 1
*/
addRange(start: number, end: number): void {
const maskL = ~0 << (start & 31)
const maskR = ~0 << (end & 31)
let i = start >> 5
if (i === end >> 5) {
this._bits[i] |= maskL ^ maskR
return
}
this._bits[i] |= maskL
for (i++; i < end >> 5; i++) {
this._bits[i] = ~0
}
this._bits[i] |= ~maskR
}
has(i: number): boolean {
return !!(this._bits[i >> 5] & (1 << (i & 31)))
}
discard(i: number): void {
this._bits[i >> 5] &= ~(1 << (i & 31))
}
/**
* [start, end) 范围内的位置为 0
*/
discardRange(start: number, end: number): void {
const maskL = ~0 << (start & 31)
const maskR = ~0 << (end & 31)
let i = start >> 5
if (i === end >> 5) {
this._bits[i] &= ~maskL | maskR
return
}
this._bits[i] &= ~maskL
for (i++; i < end >> 5; i++) {
this._bits[i] = 0
}
this._bits[i] &= maskR
}
flip(i: number): void {
this._bits[i >> 5] ^= 1 << (i & 31)
}
/**
* [start, end) 范围内的位取反
*/
flipRange(start: number, end: number): void {
const maskL = ~0 << (start & 31)
const maskR = ~0 << (end & 31)
let i = start >> 5
if (i === end >> 5) {
this._bits[i] ^= maskL ^ maskR
return
}
this._bits[i] ^= maskL
for (i++; i < end >> 5; i++) {
this._bits[i] = ~this._bits[i]
}
this._bits[i] ^= ~maskR
}
clear(): void {
this._bits.fill(0)
}
/**
* [start, end) 范围内是否全为 1
*/
allOne(start: number, end: number): boolean {
let i = start >> 5
if (i === end >> 5) {
const mask = (~0 << (start & 31)) ^ (~0 << (end & 31))
return (this._bits[i] & mask) === mask
}
let mask = ~0 << (start & 31)
if ((this._bits[i] & mask) !== mask) {
return false
}
for (i++; i < end >> 5; i++) {
if (~this._bits[i]) {
return false
}
}
mask = ~0 << (end & 31)
return !~(this._bits[end >> 5] | mask)
}
/**
* [start, end) 范围内是否全为 0
*/
allZero(start: number, end: number): boolean {
let i = start >> 5
if (i === end >> 5) {
const mask = (~0 << (start & 31)) ^ (~0 << (end & 31))
return !(this._bits[i] & mask)
}
if (this._bits[i] >> (start & 31)) {
return false
}
for (i++; i < end >> 5; i++) {
if (this._bits[i]) {
return false
}
}
const mask = ~0 << (end & 31)
return !(this._bits[end >> 5] & ~mask)
}
/**
* 返回第一个 0 的下标,若不存在则返回-1
* @param position 从哪个位置开始查找
*/
indexOfZero(position = 0): number {
if (position === 0) {
return this._indexOfZero()
}
let i = position >> 5
if (i < this._bits.length) {
let v = this._bits[i]
if (position & 31) {
v |= ~(~0 << (position & 31))
}
if (~v) {
const res = (i << 5) | BitSet._trailingZeros32(~v)
return res < this._n ? res : -1
}
for (i++; i < this._bits.length; i++) {
if (~this._bits[i]) {
const res = (i << 5) | BitSet._trailingZeros32(~this._bits[i])
return res < this._n ? res : -1
}
}
}
return -1
}
/**
* 返回第一个 1 的下标,若不存在则返回-1
* @param position 从哪个位置开始查找
*/
indexOfOne(position = 0): number {
if (!position) {
return this._indexOfOne()
}
// eslint-disable-next-line space-in-parens
for (let i = position >> 5; i < this._bits.length; ) {
const v = this._bits[i] & (~0 << (position & 31))
if (v) {
return (i << 5) | BitSet._trailingZeros32(v)
}
for (i++; i < this._bits.length; i++) {
if (this._bits[i]) {
return (i << 5) | BitSet._trailingZeros32(this._bits[i])
}
}
}
return -1
}
/**
* 返回 [start, end) 范围内 1 的个数
*/
onesCount(start = 0, end = this._n): number {
if (start < 0) {
start = 0
}
if (end > this._n) {
end = this._n
}
if (!start && end === this._n) {
return this._onesCount()
}
let pos1 = start >> 5
const pos2 = end >> 5
if (pos1 === pos2) {
return BitSet._onesCount32(this._bits[pos1] & (~0 << (start & 31)) & ((1 << (end & 31)) - 1))
}
let count = 0
if ((start & 31) > 0) {
count += BitSet._onesCount32(this._bits[pos1] & (~0 << (start & 31)))
pos1++
}
for (let i = pos1; i < pos2; i++) {
count += BitSet._onesCount32(this._bits[i])
}
if ((end & 31) > 0) {
count += BitSet._onesCount32(this._bits[pos2] & ((1 << (end & 31)) - 1))
}
return count
}
equals(other: BitSet): boolean {
if (this._bits.length !== other._bits.length) {
return false
}
for (let i = 0; i < this._bits.length; i++) {
if (this._bits[i] !== other._bits[i]) {
return false
}
}
return true
}
isSubset(other: BitSet): boolean {
if (this._bits.length > other._bits.length) {
return false
}
for (let i = 0; i < this._bits.length; i++) {
if ((this._bits[i] & other._bits[i]) >>> 0 !== this._bits[i]) {
return false
}
}
return true
}
isSuperset(other: BitSet): boolean {
if (this._bits.length < other._bits.length) {
return false
}
for (let i = 0; i < other._bits.length; i++) {
if ((this._bits[i] & other._bits[i]) >>> 0 !== other._bits[i]) {
return false
}
}
return true
}
ior(other: BitSet): void {
for (let i = 0; i < this._bits.length; i++) {
this._bits[i] |= other._bits[i]
}
}
or(other: BitSet): BitSet {
const res = new BitSet(this._bits.length)
for (let i = 0; i < this._bits.length; i++) {
res._bits[i] = this._bits[i] | other._bits[i]
}
return res
}
iand(other: BitSet): void {
for (let i = 0; i < this._bits.length; i++) {
this._bits[i] &= other._bits[i]
}
}
and(other: BitSet): BitSet {
const res = new BitSet(this._bits.length)
for (let i = 0; i < this._bits.length; i++) {
res._bits[i] = this._bits[i] & other._bits[i]
}
return res
}
copy(): BitSet {
const res = new BitSet(this._n)
res._bits.set(this._bits)
return res
}
bitLength(): number {
return this._lastIndexOfOne() + 1
}
toString(): string {
const sb: string[] = []
for (let i = 0; i < this._bits.length; i++) {
// eslint-disable-next-line newline-per-chained-call
let bits = this._bits[i].toString(2).padStart(32, '0').split('').reverse().join('')
if (i === this._bits.length - 1) {
bits = bits.slice(0, this._n & 31)
}
sb.push(bits)
}
return sb.join('')
}
_indexOfZero(): number {
for (let i = 0; i < this._bits.length; i++) {
const x = this._bits[i]
if (~x) {
return (i << 5) | BitSet._trailingZeros32(~x)
}
}
return -1
}
_indexOfOne(): number {
for (let i = 0; i < this._bits.length; i++) {
const x = this._bits[i]
if (x) {
return (i << 5) | BitSet._trailingZeros32(x)
}
}
return -1
}
_lastIndexOfOne(): number {
for (let i = this._bits.length - 1; i >= 0; i--) {
const x = this._bits[i]
if (x) {
return (i << 5) | (BitSet._bitLength32(x) - 1)
}
}
return -1
}
_onesCount(): number {
let count = 0
for (let i = 0; i < this._bits.length; i++) {
count += BitSet._onesCount32(this._bits[i])
}
return count
}
}
/**
* 布尔矩阵乘法,单次矩阵乘法的复杂度为 `O(n^3/32)`.
*/
class BooleanMatrix {
static eye(n: number): BooleanMatrix {
const res = new BooleanMatrix(n, n)
for (let i = 0; i < n; i++) res._bs[i].add(i)
return res
}
static pow(mat: BooleanMatrix, k: number): BooleanMatrix {
return mat.copy().ipow(k)
}
/**
* 5000*5000 => 80ms.
*/
static mul(mat1: BooleanMatrix, mat2: BooleanMatrix): BooleanMatrix {
return mat1.copy().imul(mat2)
}
static add(mat1: BooleanMatrix, mat2: BooleanMatrix): BooleanMatrix {
return mat1.copy().iadd(mat2)
}
readonly row: number
readonly col: number
private _bs: BitSet[]
constructor(row: number, col: number, bs?: BitSet[]) {
if (bs === void 0) {
bs = Array(row)
for (let i = 0; i < row; i++) bs[i] = new BitSet(col)
}
this.row = row
this.col = col
this._bs = bs
}
ipow(k: number): BooleanMatrix {
const res = BooleanMatrix.eye(this.row)
while (k > 0) {
if (k & 1) res.imul(this)
this.imul(this)
k = Math.floor(k / 2) // !注意不能用 `k >>>= 1`, k可能超过uint32
}
const tmp = this._bs
this._bs = res._bs
res._bs = tmp
return res
}
imul(other: BooleanMatrix): BooleanMatrix {
const row = this.row
const col = other.col
const res = new BooleanMatrix(row, col)
const otherBs = other._bs
for (let i = 0; i < row; i++) {
const rowBs = this._bs[i]
const resBs = res._bs[i]
for (let j = 0; j < col; j++) {
if (rowBs.has(j)) resBs.ior(otherBs[j])
}
}
const tmp = this._bs
this._bs = res._bs
res._bs = tmp
return res
}
iadd(mat: BooleanMatrix): BooleanMatrix {
for (let i = 0; i < this.row; i++) this._bs[i].ior(mat._bs[i])
return this
}
/**
* 求出`mat`的传递闭包`(mat+I)^n`.
* 2000*2000 => 190ms.
*/
transitiveClosure(): BooleanMatrix {
const n = this.row
const trans = BooleanMatrix.add(this, BooleanMatrix.eye(n))
trans.ipow(n)
return trans
}
copy(): BooleanMatrix {
const bs = Array(this.row)
for (let i = 0; i < this.row; i++) bs[i] = this._bs[i].copy()
return new BooleanMatrix(this.row, this.col, bs)
}
get(row: number, col: number): boolean {
return this._bs[row].has(col)
}
set(row: number, col: number, b: boolean): void {
if (b) {
this._bs[row].add(col)
} else {
this._bs[row].discard(col)
}
}
print(): void {
const grid: Uint8Array[] = Array(this.row)
for (let i = 0; i < this.row; i++) {
grid[i] = new Uint8Array(this.col)
for (let j = 0; j < this.col; j++) {
grid[i][j] = this.get(i, j) ? 1 : 0
}
}
// eslint-disable-next-line no-console
console.table(grid)
}
}
function useInput(path?: string) {
let data: string
if (path) {
data = fs.readFileSync(resolve(__dirname, path), 'utf8')
} else {
data = fs.readFileSync(process.stdin.fd, 'utf8')
}
const lines = data.split(/\r\n|\r|\n/)
let lineId = 0
const input = (): string => lines[lineId++]
return {
input
}
}
const { input } = useInput()
const [n, m, t] = input().split(' ').map(Number)
const mat = new BooleanMatrix(n, n)
for (let i = 0; i < m; i++) {
const [a, b] = input().split(' ').map(Number)
mat.set(a, b, true)
}
mat.ipow(t)
let res = 0
for (let i = 0; i < n; i++) {
res += +mat.get(0, i)
}
console.log(res)