【每日一题】(2026/3/24)【题目名称】魔法世界

题目描述:
image

输入输出描述:
image

题目思路:
题意要找出长度为nA数组的长度和B数组一样为m的子数组A'满足每个位置i都满足A'i+Bi对k的模彼此相等。
如果直接暴力:
就是遍历A中所有长度为m的数组,每次判读这每对和对k的模是否相等,时间复杂度为O(n*n)

for(int i=0;i<=n-m;i++){
  for(int j=i;j<=m-1;j++){
    //一个个判断
    if((A[j]+B[j])==(A[j+1]+B[j+1])){
    }
  }
}

如果对这个等式进行进一步的变换:
A[i]+B[i]=K的倍数+modx
A[i+1]+B[i+1]=K的倍数+modx
转变为:
(A[i]+B[i])%k=modx
(A[i+1]+B[i+1])%k=modx
那么:
(A[i+1]+B[i+1])%k-(A[i]-B[i])%k=0
(A[i+1]-A[i])%k=(B[i]-B[i+1])%k

现在就可以转变为:
先求B数组的差分,时间复杂度O(n)
再求A数组的差分,时间复杂度O(n)
然后利用差分将问题转化为有高效解法的问题。
转变为字符串匹配O(n)的超快算法(滚动哈希/KMP)

这里我使用滚动哈希,滚动哈希就是将长数组中的短数组中的元素通过自定义哈希算法进行唯一化成一个具体的数,这样方便比较。

解题思路:
先求A[i+1]-A[i]和B[i]-B[i+1]的差分

// 差分构造(和之前完全一样)
        int[] diffA = new int[n-1];
        for (int i=0; i<n-1; i++) diffA[i] = (A[i+1]-A[i]+k)%k;

        int[] target = new int[m-1];
        for (int i=0; i<m-1; i++) target[i] = (B[i]-B[i+1]+k)%k;

将B的差分数组哈希化获得一个固定的值

// 滚动哈希:O(n + m) 高效匹配
        long hashT = 0, base = 911382629L;
        for (int num : target) hashT = hashT * base + num;

初始化A的哈希值

        long hashA = 0, pow = 1;
        for (int i=0; i<target.length; i++) {
            hashA = hashA * base + diffA[i];
            pow *= base;
        }

滚动哈希

int count = hashA == hashT ? 1 : 0;
        for (int i=target.length; i<diffA.length; i++) {
            hashA = hashA * base + diffA[i] - diffA[i-target.length] * pow;
            if (hashA == hashT) count++;
        }

滚动哈希就是把经典的暴力解法(数组中长度为n的子数组完全匹配问题)(时间复杂度是n*n)转变为O(n)

整体代码:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt(), m = scan.nextInt(), k = scan.nextInt();
        int[] A = new int[n], B = new int[m];
        for (int i=0; i<n; i++) A[i] = scan.nextInt();
        for (int i=0; i<m; i++) B[i] = scan.nextInt();

        // 差分构造(和之前完全一样)
        int[] diffA = new int[n-1];
        for (int i=0; i<n-1; i++) diffA[i] = (A[i+1]-A[i]+k)%k;

        int[] target = new int[m-1];
        for (int i=0; i<m-1; i++) target[i] = (B[i]-B[i+1]+k)%k;

        // 特殊情况:m=1时,所有位置都合法
        if (m == 1) {
            System.out.println(n);
            return;
        }

        // 滚动哈希:O(n + m) 高效匹配
        long hashT = 0, base = 911382629L;
        for (int num : target) hashT = hashT * base + num;

        long hashA = 0, pow = 1;
        for (int i=0; i<target.length; i++) {
            hashA = hashA * base + diffA[i];
            pow *= base;
        }

        int count = hashA == hashT ? 1 : 0;
        for (int i=target.length; i<diffA.length; i++) {
            hashA = hashA * base + diffA[i] - diffA[i-target.length] * pow;
            if (hashA == hashT) count++;
        }

        System.out.println(count);
    }
}
posted @ 2026-03-24 15:23  Jwwind  阅读(9)  评论(1)    收藏  举报