【算法训练营】矩形,回文串(Python实现)

矩形


描述

给定两个矩阵,判断第二个矩阵在第一个矩阵的哪些位置出现过。

输入

输入的第一行包含四个正整数a,b,c,d,表示第一个矩阵大小为a×b,第二个矩阵的大小为c×d。

接下来是一个a×b的矩阵。

再接下来是一个c×d的矩阵。

保证矩阵中每个数字都为正整数且不超过100。

输出

若第二个矩阵在第一个矩阵的(i,j)位置出现(即出现位置的左上角),输出i和j。若有多个位置,按字典序从小到大的顺序依次输出。

字典序:对于两个位置(a,b),(c,d),若a<c则(a,b)比(c,d)小,若a>c则(a,b)比(c,d)大,若a=c则再像前边一样比较b和d。

样例1输入

4 4 2 2
1 2 1 2
2 3 2 3
2 1 2 3
2 2 3 1
1 2
2 3

样例1输出

1 1
1 3
3 2

样例1解释

矩阵2在矩阵1的(1,1)、(1,3)、(3,2)这些位置出现了。

样例2

请查看下发文件内的sample2_input.txt和sample2_output.txt。

限制

对于50%的数据,a,b,c,d ≤ 50;

对于100%的数据,a,b,c,d ≤ 1000。

时间:4 sec

空间:512 MB

代码实现

from typing import List, Tuple

def get_answer(n: int, m:int, p: int, q: int, a: List[List[int]], b: List[List[int]]) -> List[Tuple[int, int]]:
    mo1, mo2, pw, N = 1000000007, 1000000009, 233, 1005
    h1, h2, bb = [[[0] * N for _ in range(N)] for _ in range(2)], [[[0] * N for _ in range(N)] for _ in range(2)], [[[0] * N for _ in range(N)] for _ in range(2)]

    p1 = p2 = 1
    for _ in range(q):
        p1 = p1 * pw % mo1
        p2 = p2 * pw % mo2
    p1 = (mo1 - p1) % mo1
    p2 = (mo2 - p2) % mo2

    for i in range(1, n + 1):
        t1 = t2 = 0
        for j in range(1, m + 1):
            if j < q:
                t1 = (t1 * pw + a[i][j]) % mo1
                t2 = (t2 * pw + a[i][j]) % mo2
            else:
                t1 = h1[0][i][j] = (t1 * pw + a[i][j] + p1 * a[i][j - q]) % mo1
                t2 = h2[0][i][j] = (t2 * pw + a[i][j] + p2 * a[i][j - q]) % mo2

    p1 = p2 = 1
    for _ in range(p):
        p1 = p1 * pw % mo1
        p2 = p2 * pw % mo2
    p1 = (mo1 - p1) % mo1
    p2 = (mo2 - p2) % mo2

    for j in range(1, m + 1):
        t1 = t2 = 0
        for i in range(1, n + 1):
            if i < p:
                t1 = (t1 * pw + h1[0][i][j]) % mo1
                t2 = (t2 * pw + h2[0][i][j]) % mo2
            else:
                t1 = h1[1][i][j] = (t1 * pw + h1[0][i][j] + p1 * h1[0][i - p][j]) % mo1
                t2 = h2[1][i][j] = (t2 * pw + h2[0][i][j] + p2 * h2[0][i - p][j]) % mo2

    for i in range(1, p + 1):
        for j in range(1, q + 1):
            bb[0][i][j] = (bb[0][i][j - 1] * pw + b[i][j]) % mo1
            bb[1][i][j] = (bb[1][i][j - 1] * pw + b[i][j]) % mo2

    p1 = p2 = 0
    for i in range(1, p + 1):
        p1 = (p1 * pw + bb[0][i][q]) % mo1
        p2 = (p2 * pw + bb[1][i][q]) % mo2

    ans = []
    for i in range(p, n + 1):
        for j in range(q, m + 1):
            if h1[1][i][j] == p1 and h2[1][i][j] == p2:
                ans.append((i - p + 1, j - q + 1))

    return ans


def main():
    n, m, p, q = map(int, input().split())
    a = [[0] * (m + 1) for _ in range(n + 1)]
    b = [[0] * (q + 1) for _ in range(p + 1)]

    for i in range(1, n + 1):
        a[i][1:] = list(map(int, input().split()))

    for i in range(1, p + 1):
        b[i][1:] = list(map(int, input().split()))

    result = get_answer(n, m, p, q, a, b)

    for r in result:
        print(r[0], r[1])

if __name__ == "__main__":
    main()

回文串


描述

给定一个字符串,求出该字符串有多少子串是回文串。

子串:字符串中连续的一段。比如字符串abcd里,bc、abc、a、bcd都是子串。

回文串:字符串倒序写出来和该字符串相同。比如aba,倒序写出来也是aba,故aba是回文串。而abab不是回文串,因为倒过来写是baba。

输入

输入一个字符串。

输出

输出子串是回文串的个数。

样例1输入

abab

样例1输出

6

样例1解释

abab,abab,abab

abab,abab,abab

样例2

请查看下发文件内的sample2_input.txt和sample2_output.txt。

限制

对于50%的数据,字符串长度不超过500;

对于70%的数据,字符串长度不超过2000;

对于100%的数据,字符串长度不超过500000。

字符串为26个小写字母组成。

时间:2 sec

空间:512 MB

提示

[[[https://segmentfault.com/a/1190000003914228]

[这篇文章是求最长的回文串的,那么如何求回文串的数目呢?可以发现manacher算法将每个位置为中心能延展出的最长回文串求出来了,那么这个最长回文串的一半(上取整)就是以该点作为中心的回文串数目。]

[注意答案要用long long。]

代码实现 

def get_answer(s: str) -> int:
    n = len(s)
    new_s = [""] * (n * 2 + 4)
    new_len = [0] * (n * 2 + 4)

    for i in range(n):
        new_s[i * 2 + 2] = s[i]
        new_s[i * 2 + 3] = ''

    n = n * 2 + 1
    new_s[1] = ''
    new_s[0] = '1'
    new_s[n + 1] = '2'

    cur = 1
    ans = 0
    for i in range(2, n + 1):
        if cur + new_len[cur] > i:
            pos = (cur * 2) - i
            new_len[i] = min(new_len[pos], cur + new_len[cur] - i)
        else:
            new_len[i] = 0

        while new_s[i - new_len[i] - 1] == new_s[i + new_len[i] + 1]:
            new_len[i] += 1

        if i + new_len[i] > cur + new_len[cur]:
            cur = i

        ans += (new_len[i] + 1) // 2

    return ans


def main():
    s = input()
    result = get_answer(s)
    print(result)


if __name__ == "__main__":
    main()

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

X.AI666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值