近似回文

[题目链接](https://www.nowcoder.com/practice/6da3c8db8de040e29908efd855c562ae)

思路

本题要求长度为 的小写字母串中,满足"非回文但删去恰好一个字符后可变为回文"的串的个数,结果对 取模。

双指针分析结构

对于一个非回文串 ,用双指针从两端向中间匹配:,... 设第一个失配出现在深度 ,即 成立,但

要让删除一个字符后变为回文,只有两种可能:

  • 删左端:删去 ,需要内部子串 本身是回文。
  • 删右端:删去 ,需要内部子串 本身是回文。

可以证明,对于任何近似回文串,有效的删除位置一定包含第一个失配处的左端或右端(或两者都可),因此按失配深度 分类能不重不漏地枚举所有近似回文串。

分类计数

固定失配深度 ,令内部长度

选项 A(删左端)的方案数:外层 对匹配字符有 种选法;内部回文 长度为 ,自由位有 个,共 种; 可以取除 以外的任意字母( 种)。所以:

$$

由对称性,选项 B 的方案数

两者同时成立(CountAB):此时 都是长度 的回文。分析可得内部必须以周期 2 交替:,且

  • 为偶数时 为偶数,交替结构自洽:
  • 为奇数时 为奇数,交替结构产生矛盾:

由容斥,每个深度 的贡献为

化简闭合公式

关键观察:当 为偶数, 为奇数,,所以 无关

为奇数,,同样 ,与 无关。

对所有合法深度求和:

  • 为偶数):

$$

其中几何级数求和

  • 为奇数):

$$

特殊情况

时,所有串都是回文,答案为

最终只需一次快速幂和常数次乘法即可求解。

代码

#include <bits/stdc++.h>
using namespace std;

const long long MOD = 998244353;

long long power(long long base, long long exp, long long mod) {
    long long result = 1;
    base %= mod;
    while (exp > 0) {
        if (exp & 1) result = result * base % mod;
        base = base * base % mod;
        exp >>= 1;
    }
    return result;
}

int main() {
    long long n;
    scanf("%lld", &n);
    if (n <= 1) {
        printf("0\n");
        return 0;
    }
    long long ans;
    if (n % 2 == 0) {
        long long h = n / 2;
        long long p = power(26, h, MOD);
        long long coeff = (25LL * n % MOD - 26 + MOD) % MOD;
        ans = (p % MOD * coeff % MOD + 26) % MOD;
    } else {
        long long h = (n - 1) / 2;
        long long p = power(26, h, MOD);
        ans = 25LL % MOD * ((n - 1) % MOD) % MOD * p % MOD;
    }
    printf("%lld\n", ans);
    return 0;
}
import java.util.Scanner;

public class Main {
    static final long MOD = 998244353;

    static long power(long base, long exp, long mod) {
        long result = 1;
        base %= mod;
        while (exp > 0) {
            if ((exp & 1) == 1) result = result * base % mod;
            base = base * base % mod;
            exp >>= 1;
        }
        return result;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long n = sc.nextLong();
        if (n <= 1) {
            System.out.println(0);
            return;
        }
        long ans;
        if (n % 2 == 0) {
            long h = n / 2;
            long p = power(26, h, MOD);
            long coeff = (25L * n % MOD - 26 + MOD) % MOD;
            ans = (p * coeff % MOD + 26) % MOD;
        } else {
            long h = (n - 1) / 2;
            long p = power(26, h, MOD);
            ans = 25L % MOD * ((n - 1) % MOD) % MOD * p % MOD;
        }
        System.out.println(ans);
    }
}
import sys

def power(base, exp, mod):
    return pow(base, exp, mod)

def main():
    n = int(sys.stdin.readline())
    MOD = 998244353
    if n <= 1:
        print(0)
        return
    if n % 2 == 0:
        h = n // 2
        p = power(26, h, MOD)
        coeff = (25 * n - 26) % MOD
        ans = (p * coeff + 26) % MOD
    else:
        h = (n - 1) // 2
        p = power(26, h, MOD)
        ans = 25 * (n - 1) % MOD * p % MOD
    print(ans)

main()
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin });

function power(base, exp, mod) {
    let result = 1n;
    base = base % mod;
    while (exp > 0n) {
        if (exp & 1n) result = result * base % mod;
        base = base * base % mod;
        exp >>= 1n;
    }
    return result;
}

rl.on('line', (line) => {
    const n = BigInt(line.trim());
    const MOD = 998244353n;
    if (n <= 1n) {
        console.log("0");
        return;
    }
    let ans;
    if (n % 2n === 0n) {
        const h = n / 2n;
        const p = power(26n, h, MOD);
        const coeff = (25n * n % MOD - 26n + MOD) % MOD;
        ans = (p * coeff % MOD + 26n) % MOD;
    } else {
        const h = (n - 1n) / 2n;
        const p = power(26n, h, MOD);
        ans = 25n * ((n - 1n) % MOD) % MOD * p % MOD;
    }
    console.log(ans.toString());
});

复杂度分析

  • 时间复杂度: ,来自快速幂。
  • 空间复杂度: