結果
問題 | No.1340 おーじ君をさがせ |
ユーザー | 草苺奶昔 |
提出日時 | 2023-06-05 13:55:07 |
言語 | Go (1.22.1) |
結果 |
AC
|
実行時間 | 25 ms / 2,000 ms |
コード長 | 8,103 bytes |
コンパイル時間 | 12,437 ms |
コンパイル使用メモリ | 229,184 KB |
実行使用メモリ | 7,916 KB |
最終ジャッジ日時 | 2024-06-09 05:09:44 |
合計ジャッジ時間 | 14,441 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1 ms
6,812 KB |
testcase_01 | AC | 2 ms
6,816 KB |
testcase_02 | AC | 2 ms
6,812 KB |
testcase_03 | AC | 1 ms
6,944 KB |
testcase_04 | AC | 1 ms
6,940 KB |
testcase_05 | AC | 1 ms
6,940 KB |
testcase_06 | AC | 1 ms
6,940 KB |
testcase_07 | AC | 1 ms
6,944 KB |
testcase_08 | AC | 2 ms
6,940 KB |
testcase_09 | AC | 1 ms
6,944 KB |
testcase_10 | AC | 2 ms
6,940 KB |
testcase_11 | AC | 7 ms
6,940 KB |
testcase_12 | AC | 3 ms
6,940 KB |
testcase_13 | AC | 6 ms
6,940 KB |
testcase_14 | AC | 8 ms
6,940 KB |
testcase_15 | AC | 8 ms
6,940 KB |
testcase_16 | AC | 3 ms
6,940 KB |
testcase_17 | AC | 4 ms
6,940 KB |
testcase_18 | AC | 6 ms
6,940 KB |
testcase_19 | AC | 3 ms
6,944 KB |
testcase_20 | AC | 2 ms
6,940 KB |
testcase_21 | AC | 14 ms
6,944 KB |
testcase_22 | AC | 18 ms
7,784 KB |
testcase_23 | AC | 14 ms
6,940 KB |
testcase_24 | AC | 19 ms
7,912 KB |
testcase_25 | AC | 11 ms
6,944 KB |
testcase_26 | AC | 7 ms
6,940 KB |
testcase_27 | AC | 6 ms
6,944 KB |
testcase_28 | AC | 11 ms
6,940 KB |
testcase_29 | AC | 6 ms
6,940 KB |
testcase_30 | AC | 14 ms
6,944 KB |
testcase_31 | AC | 25 ms
7,912 KB |
testcase_32 | AC | 23 ms
7,916 KB |
testcase_33 | AC | 23 ms
7,916 KB |
testcase_34 | AC | 22 ms
7,912 KB |
testcase_35 | AC | 25 ms
7,912 KB |
testcase_36 | AC | 2 ms
6,944 KB |
testcase_37 | AC | 9 ms
6,944 KB |
testcase_38 | AC | 24 ms
7,912 KB |
testcase_39 | AC | 12 ms
6,940 KB |
testcase_40 | AC | 12 ms
6,940 KB |
testcase_41 | AC | 12 ms
6,940 KB |
testcase_42 | AC | 1 ms
6,940 KB |
testcase_43 | AC | 2 ms
6,940 KB |
testcase_44 | AC | 2 ms
6,940 KB |
testcase_45 | AC | 2 ms
6,940 KB |
testcase_46 | AC | 6 ms
6,940 KB |
testcase_47 | AC | 6 ms
6,944 KB |
testcase_48 | AC | 7 ms
6,944 KB |
testcase_49 | AC | 5 ms
6,944 KB |
testcase_50 | AC | 5 ms
6,944 KB |
testcase_51 | AC | 4 ms
6,944 KB |
testcase_52 | AC | 8 ms
6,940 KB |
testcase_53 | AC | 8 ms
6,940 KB |
testcase_54 | AC | 8 ms
6,944 KB |
testcase_55 | AC | 7 ms
6,940 KB |
testcase_56 | AC | 2 ms
6,944 KB |
testcase_57 | AC | 2 ms
6,940 KB |
testcase_58 | AC | 2 ms
6,940 KB |
testcase_59 | AC | 3 ms
6,944 KB |
testcase_60 | AC | 2 ms
6,944 KB |
testcase_61 | AC | 3 ms
6,940 KB |
ソースコード
package main import ( "bufio" "fmt" "math/bits" "math/rand" "os" "strings" "time" ) func main() { yuki1340() // test() } // https://yukicoder.me/problems/no/1340 // 给定一个n个点m条边的有向图,求t步后可能所在的顶点个数(每一步必须移动到一个相邻点). // n<=100 m<=1e4 t<=1e18 func yuki1340() { in := bufio.NewReader(os.Stdin) out := bufio.NewWriter(os.Stdout) defer out.Flush() var n, m, t int fmt.Fscan(in, &n, &m, &t) mat := NewBooleanSquareMatrix(n) for i := 0; i < m; i++ { var a, b int fmt.Fscan(in, &a, &b) mat.Set(a, b, true) } mat.IPow(t) res := 0 for i := 0; i < n; i++ { if mat.Get(0, i) { res++ } } fmt.Fprintln(out, res) } // https://leetcode.cn/problems/course-schedule-iv/ func checkIfPrerequisite(numCourses int, prerequisites [][]int, queries [][]int) []bool { mat := NewBooleanSquareMatrix(numCourses) for _, p := range prerequisites { mat.Set(p[0], p[1], true) } trans := mat.TransitiveClosure() res := make([]bool, len(queries)) for i, q := range queries { res[i] = trans.Get(q[0], q[1]) } return res } func test() { mat := NewBooleanSquareMatrix(3) mat.Set(0, 0, true) mat.Set(0, 1, true) mat.Set(1, 2, true) mat.Set(1, 0, true) testRandom := func() { fmt.Println(strings.Repeat("=", 20)) fmt.Println("测试随机矩阵") // !随机01矩阵 // 5000*5000的矩阵乘法 => 697.955ms N_5000 := 5000 mat := NewBooleanSquareMatrix(N_5000) for i := 0; i < N_5000; i++ { for j := 0; j < N_5000; j++ { if rand.Intn(2) == 0 { mat.Set(i, j, true) } } } time1 := time.Now() Mul(mat, mat) time2 := time.Now() fmt.Println(fmt.Sprintf("5000*5000的矩阵乘法:%v", time2.Sub(time1))) // 2000*2000的传递闭包 => 830.0099ms N_2000 := 2000 mat = NewBooleanSquareMatrix(N_2000) for i := 0; i < N_2000; i++ { for j := 0; j < N_2000; j++ { if rand.Intn(2) == 0 { mat.Set(i, j, true) } } } time3 := time.Now() mat.TransitiveClosure() time4 := time.Now() fmt.Println(fmt.Sprintf("2000*2000的传递闭包:%v", time4.Sub(time3))) } testSparse := func() { fmt.Println(strings.Repeat("=", 20)) fmt.Println("测试稀疏矩阵") // !稀疏矩阵 // 5000*5000的矩阵乘法 => 548.3657ms N_5000 := 5000 mat := NewBooleanSquareMatrix(N_5000) for i := 0; i < N_5000; i++ { for j := 0; j < N_5000; j++ { if rand.Intn(10) == 0 { mat.Set(i, j, true) } } } time1 := time.Now() Mul(mat, mat) time2 := time.Now() fmt.Println(fmt.Sprintf("5000*5000的矩阵乘法:%v", time2.Sub(time1))) // 2000*2000的传递闭包 => 817.5958ms N_2000 := 2000 mat = NewBooleanSquareMatrix(N_2000) for i := 0; i < N_2000; i++ { for j := 0; j < N_2000; j++ { if rand.Intn(10) == 0 { mat.Set(i, j, true) } } } time3 := time.Now() mat.TransitiveClosure() time4 := time.Now() fmt.Println(fmt.Sprintf("2000*2000的传递闭包:%v", time4.Sub(time3))) } testDense := func() { fmt.Println(strings.Repeat("=", 20)) fmt.Println("测试稠密矩阵") // !稠密矩阵 // 5000*5000的矩阵乘法 => 491.0388ms N_5000 := 5000 mat := NewBooleanSquareMatrix(N_5000) for i := 0; i < N_5000; i++ { for j := 0; j < N_5000; j++ { mat.Set(i, j, true) } } time1 := time.Now() Mul(mat, mat) time2 := time.Now() fmt.Println(fmt.Sprintf("5000*5000的矩阵乘法:%v", time2.Sub(time1))) // 2000*2000的传递闭包 => 827.1923ms N_2000 := 2000 mat = NewBooleanSquareMatrix(N_2000) for i := 0; i < N_2000; i++ { for j := 0; j < N_2000; j++ { mat.Set(i, j, true) } } time3 := time.Now() mat.TransitiveClosure() time4 := time.Now() fmt.Println(fmt.Sprintf("2000*2000的传递闭包:%v", time4.Sub(time3))) } testRandom() testSparse() testDense() } // trailing zero table var _BSF [1e4 + 10]int func init() { for i := range _BSF { _BSF[i] = bits.TrailingZeros(uint(i)) } } // 布尔方阵. type BooleanSquareMatrix struct { N int bs []Bitset dp []Bitset // 在计算矩阵乘法时用到 } // n<=1e4. func NewBooleanSquareMatrix(n int) *BooleanSquareMatrix { bs := make([]Bitset, n) for i := range bs { bs[i] = NewBitset(n) } return &BooleanSquareMatrix{N: n, bs: bs} } // n<=1e4. func Eye(n int) *BooleanSquareMatrix { res := NewBooleanSquareMatrix(n) for i := 0; i < n; i++ { res.bs[i].Set(i) } return res } func Pow(mat *BooleanSquareMatrix, k int) *BooleanSquareMatrix { return mat.Copy().IPow(k) } func Mul(mat1, mat2 *BooleanSquareMatrix) *BooleanSquareMatrix { return mat1.Copy().IMul(mat2) } func Add(mat1, mat2 *BooleanSquareMatrix) *BooleanSquareMatrix { return mat1.Copy().IAdd(mat2) } // (A + I)^n 是传递闭包. func (bm *BooleanSquareMatrix) TransitiveClosure() *BooleanSquareMatrix { n := bm.N newMat := Eye(n).IAdd(bm) newMat.IPow(n) return newMat } func (bm *BooleanSquareMatrix) IPow(k int) *BooleanSquareMatrix { res := Eye(bm.N) for k > 0 { if k&1 == 1 { res.IMul(bm) } bm.IMul(bm) k >>= 1 } res.bs, bm.bs = bm.bs, res.bs return bm } // O(n^3/wlogn),这里logn指的是分块的大小. func (bm *BooleanSquareMatrix) IMul(mat *BooleanSquareMatrix) *BooleanSquareMatrix { n := mat.N res := NewBooleanSquareMatrix(n) step := 8 // !理论最优是logn,实际取8效果最好(n为5000时) bm._createDpIfAbsent(step, n) dp := bm.dp for l, r := 0, step; l != n; l, r = r, r+step { if r > n { r = n } for s := 1; s < (1 << step); s++ { bsf := _BSF[s] if l+bsf < n { dp[s] = Or(dp[s^(1<<bsf)], mat.bs[l+bsf]) // Xor => f2矩阵乘法 } else { dp[s] = dp[s^(1<<bsf)] } } for i, now := 0, 0; i != n; i, now = i+1, 0 { for j := l; j != r; j++ { if bm.bs[i].Has(j) { now ^= 1 << (j - l) } } res.bs[i].IOr(dp[now]) // IXor => f2矩阵乘法 } } bm.bs, res.bs = res.bs, bm.bs return res } func (bm *BooleanSquareMatrix) IAdd(mat *BooleanSquareMatrix) *BooleanSquareMatrix { for i := 0; i < bm.N; i++ { bm.bs[i].IOr(mat.bs[i]) } return bm } func (bm *BooleanSquareMatrix) Copy() *BooleanSquareMatrix { bs := make([]Bitset, bm.N) for i := range bs { bs[i] = bm.bs[i].Copy() } return &BooleanSquareMatrix{N: bm.N, bs: bs, dp: bm.dp} } func (bm *BooleanSquareMatrix) Get(row, col int) bool { return bm.bs[row].Has(col) } func (bm *BooleanSquareMatrix) Set(row, col int, b bool) { if b { bm.bs[row].Set(col) } else { bm.bs[row].Reset(col) } } // To 2D grid. func (mat *BooleanSquareMatrix) String() string { n := mat.N grid := make([][]int, n) for i := 0; i < n; i++ { grid[i] = make([]int, n) for j := 0; j < n; j++ { if mat.Get(i, j) { grid[i][j] = 1 } else { grid[i][j] = 0 } } } sb := strings.Builder{} sb.WriteString(fmt.Sprintf("BooleanSquareMatrix(%d,%d)\n", n, n)) for i := 0; i < n; i++ { for j := 0; j < n; j++ { sb.WriteString(fmt.Sprintf("%d ", grid[i][j])) } sb.WriteString("\n") } return sb.String() } func (mat *BooleanSquareMatrix) _createDpIfAbsent(step int, n int) { if mat.dp == nil { dp := make([]Bitset, 1<<step) for i := range dp { dp[i] = NewBitset(n) } mat.dp = dp } } const _w = bits.UintSize type Bitset []uint func NewBitset(n int) Bitset { return make(Bitset, n/_w+1) } // (n+_w-1)/_w func (b Bitset) Has(p int) bool { return b[p/_w]&(1<<(p%_w)) != 0 } func (b Bitset) Flip(p int) { b[p/_w] ^= 1 << (p % _w) } func (b Bitset) Set(p int) { b[p/_w] |= 1 << (p % _w) } func (b Bitset) Reset(p int) { b[p/_w] &^= 1 << (p % _w) } func (b Bitset) Copy() Bitset { res := make(Bitset, len(b)) copy(res, b) return res } // 将 c 的元素合并进 b func (b Bitset) IOr(c Bitset) Bitset { for i, v := range c { b[i] |= v } return b } // !f2上的加法 func (b Bitset) IXOr(c Bitset) { for i, v := range c { b[i] ^= v } } func Or(a, b Bitset) Bitset { res := make(Bitset, len(a)) for i, v := range a { res[i] = v | b[i] } return res } func Xor(a, b Bitset) Bitset { res := make(Bitset, len(a)) for i, v := range a { res[i] = v ^ b[i] } return res }