結果

問題 No.263 Common Palindromes Extra
ユーザー 草苺奶昔草苺奶昔
提出日時 2024-02-18 02:27:23
言語 Go
(1.22.1)
結果
MLE  
実行時間 -
コード長 2,793 bytes
コンパイル時間 13,394 ms
コンパイル使用メモリ 222,648 KB
実行使用メモリ 246,032 KB
最終ジャッジ日時 2024-02-18 02:27:39
合計ジャッジ時間 15,776 ms
ジャッジサーバーID
(参考情報)
judge16 / judge13
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 8 ms
6,676 KB
testcase_01 AC 1 ms
6,676 KB
testcase_02 AC 1 ms
6,676 KB
testcase_03 AC 18 ms
10,216 KB
testcase_04 AC 77 ms
29,192 KB
testcase_05 AC 98 ms
27,024 KB
testcase_06 AC 9 ms
7,812 KB
testcase_07 AC 188 ms
84,416 KB
testcase_08 AC 213 ms
82,248 KB
testcase_09 AC 314 ms
137,640 KB
testcase_10 MLE -
testcase_11 AC 67 ms
28,904 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	yuki263()
}

// No.263 Common Palindromes Extra
// 求两个字符串的公共回文子串的个数 n<=5e5
// https://yukicoder.me/problems/no/263
func yuki263() {
	in := bufio.NewReader(os.Stdin)
	out := bufio.NewWriter(os.Stdout)
	defer out.Flush()

	var s, t string
	fmt.Fscan(in, &s, &t)
	T := NewPam()
	T.AddString(s + "><" + t)
	dps := make([]int, T.Size())
	dpt := make([]int, T.Size())
	lenS := int32(len(s))
	for i := 0; i < T.Size(); i++ {
		for _, j := range T.Nodes[i].Indexes { // 回文出现位置
			if j < lenS {
				dps[i]++
			} else if j >= lenS+2 {
				dpt[i]++
			}
		}
	}

	res := 0
	for i := T.Size() - 1; i >= 2; i-- { // 按照拓扑序遍历本质不同回文
		res += dps[i] * dpt[i]
		dps[T.Nodes[i].Link] += dps[i]
		dpt[T.Nodes[i].Link] += dpt[i]
	}
	fmt.Fprintln(out, res)
}

type Node struct {
	Next    map[int32]int32 // 子节点.
	Link    int32           // suffix link,指向当前回文串的最长真回文后缀的位置
	Length  int32           // 结点代表的回文串的长度
	Indexes []int32         // 哪些位置的最长回文后缀
}

type Pam struct {
	Ords    []int32
	Nodes   []*Node
	lastPos int32 // 当前字符串(原串前缀)的最长回文后缀
}

func NewPam() *Pam {
	res := &Pam{}
	res.Nodes = append(res.Nodes, res.newNode(0, -1)) // 奇根,长为 -1
	res.Nodes = append(res.Nodes, res.newNode(0, 0))  // 偶根,长为 0
	return res
}

func (pt *Pam) Add(x int32) int {
	pos := int32(len(pt.Ords))
	pt.Ords = append(pt.Ords, x)
	cur := pt.findPrevPalindrome(pt.lastPos)
	_, hasKey := pt.Nodes[cur].Next[x]
	if !hasKey {
		pt.Nodes[cur].Next[x] = int32(len(pt.Nodes))
	}
	pt.lastPos = pt.Nodes[cur].Next[x]
	if !hasKey {
		pt.Nodes = append(pt.Nodes, pt.newNode(-1, pt.Nodes[cur].Length+2))
		if pt.Nodes[len(pt.Nodes)-1].Length == 1 {
			pt.Nodes[len(pt.Nodes)-1].Link = 1
		} else {
			pt.Nodes[len(pt.Nodes)-1].Link = pt.Nodes[pt.findPrevPalindrome(pt.Nodes[cur].Link)].Next[x]
		}
	}

	pt.Nodes[pt.lastPos].Indexes = append(pt.Nodes[pt.lastPos].Indexes, pos)
	return int(pt.lastPos)
}

func (pt *Pam) AddString(s string) {
	if len(s) == 0 {
		return
	}
	for _, v := range s {
		pt.Add(v)
	}
}

func (pt *Pam) Size() int {
	return len(pt.Nodes)
}

func (pt *Pam) GetNode(pos int) *Node {
	return pt.Nodes[pos]
}

func (pt *Pam) newNode(link, length int32) *Node {
	return &Node{
		Next:   make(map[int32]int32),
		Link:   link,
		Length: length,
	}
}

func (pt *Pam) findPrevPalindrome(cur int32) int32 {
	pos := int32(len(pt.Ords) - 1)
	for {
		rev := pos - 1 - pt.Nodes[cur].Length
		// !插入当前字符的条件str[i]==str[i-len-1]
		if rev >= 0 && pt.Ords[rev] == pt.Ords[len(pt.Ords)-1] {
			break
		}
		cur = pt.Nodes[cur].Link
	}
	return cur
}
0