定长滑动窗口篇--罗姆的刷题记录

题单来自灵神,这里针对我的刷题过程做一个记录,本系列的目的是记录心得+做题记录的统计

1456. 定长子串中元音的最大数目 1263

题意:找到字符串 s 中长为 k 的串中包含元音最多的数量。 可能踩坑:进出区间判断下标范围。
踩坑:数组存在负数,初始化INT_MIN。

INT_MIN `INT_MIN` 是 C/C++ 中 `int` 类型的最小值,定义在 ``(C++ 用)或 ``(C 用)中。

值: 通常是 -2147483648(即 -2^31,32位系统)

用法:

#include <climits>

int maxVal = INT_MIN; // 初始化为最小值,用于求最大值
for (int x : nums) {
    maxVal = max(maxVal, x);
}

常见场景:
- 求最大值时初始化变量
- 判断溢出边界

注意事项:
- INT_MIN 取反会溢出:-INT_MIN 是未定义行为
- 如果用 LeetCode / 力扣,<climits> 通常已经可以直接用,不需要额外 include

相关常量:

┌───────────┬──────────────────────┐
│   常量    │          值          │
├───────────┼──────────────────────┤
│ INT_MIN   │ -2147483648          │
├───────────┼──────────────────────┤
│ INT_MAX   │ 2147483647           │
├───────────┼──────────────────────┤
│ LLONG_MIN │ -9223372036854775808 │
├───────────┼──────────────────────┤
│ LLONG_MAX │ 9223372036854775807  │
└───────────┴──────────────────────┘
点击展开代码
class Solution {
public:
    bool isVol(char c) {
        return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
    }
    int maxVowels(string s, int k) {
        int n = s.size();
        int res = 0, cnt = 0;
        for (int i = 0; i < n; i++) {
            if (isVol(s[i])) {
                cnt++;
            }
            if (i - k + 1 >= 0) {
                res = max(res, cnt);
            }
            if (i - k + 1 >= 0 && isVol(s[i - k + 1])) {
                cnt--;
            }
        }
        return res;
    }
};

643. 子数组最大平均数 I

题意:给一个数组和一个整数k,求平均数最大的长为k的连续子数组的最大平均数。

点击展开代码
class Solution {
public:
    double findMaxAverage(vector<int>& nums, int k) {
        double sum = 0, res = INT_MIN;
        int n = nums.size();
        for (int i = 0; i < n; i++) {
            sum += nums[i];
            if (i - k + 1 >= 0) {
                res = max(res, sum);
            }
            if (i - k + 1 >= 0) {
                sum -= nums[i - k + 1];
            }
        }
        return res / k;
    }
};

1343. 大小为 K 且平均值大于等于阈值的子数组数目 1317

题意:给一个整数数组arr,两个整数k和threshold。返回长度为k且平均值大于等于threshhold的子数组数目。

class Solution {
public:
    int numOfSubarrays(vector<int>& arr, int k, int threshold) {
        int n = arr.size();
        int res = 0;
        long long sum = 0;
        for (int i = 0; i < n; i++) {
            sum += arr[i];
            if (i - k + 1 >= 0) {
                if (sum >= threshold * k)
                    res++;
            }
            if (i - k + 1 >= 0)
                sum -= arr[i - k + 1];
        }
        return res;
    }
};

2090. 半径为 k 的子数组平均值 1358

题意:给一个数组nums,n个整数。一个整数k。定义半径为k的子数组平均值:以i 为中心且半径为k的子数组所有元素的平均值。如果不足k个元素,均值为-1. 构建一个长为n的数组avg,其中avg[i]表示下标 i 为中心的子数组的半径为k的子数组均值。均值采用整除截断。

注意整数溢出问题

code
class Solution {
public:
    vector<int> getAverages(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> avg(n, -1);
        long long sum = 0;
        int l;
        // assume center i . current r . i  + k = r ,  i - k = l =>  i = r - k ,
        // l = r - k - k
        for (int r = 0; r < n; r++) {
            sum += nums[r];
            l = r - k - k;
            if (l >= 0)
                avg[r - k] = sum / (r - l + 1);
            if (l >= 0)
                sum -= nums[l];
        }
        return avg;
    }
};

2379. 得到 K 个黑块的最少涂色次数 1360

题意:给一个长为n的字符串blocks,blocks[i]要么是W要么是B,表示颜色。给一个k,表示想要连续黑色的数目,每次操作可以把一个白色涂成黑色,求最小操作次数。

code
class Solution {
public:
    int minimumRecolors(string blocks, int k) {
        int n = blocks.size();
        int res = n, cb = 0;
        // same as k area => max B or min W
        for (int i = 0; i < n; i++) {
            if (blocks[i] == 'B')
                cb++;
            if (i - k + 1 >= 0)
                res = min(res, k - cb);
            if (i - k + 1 >= 0 && blocks[i - k + 1] == 'B')
                cb--;
        }
        return res;
    }
};

2841. 几乎唯一子数组的最大和 1546

题意:给一个整数数组nums,两个整数m和k。返回nums中长度为k的几乎唯一子数组的最大和,不存在返回0.
几乎唯一子数组:如果nums一个子数组至少有m个互不相同的元素。

code
class Solution {
public:
    long long maxSum(vector<int>& nums, int m, int k) {
        int n = nums.size();
        unordered_map<int, int> mp;
        long long res = 0, sum = 0;
        int diffcnt = 0;

        for (int i = 0; i < n; i++) {
            sum += nums[i];
            if (!mp[nums[i]]) { // push
                diffcnt++;
            }
            mp[nums[i]]++;
            if (diffcnt >= m) {
                res = max(res, sum);
            }
            if (i - k + 1 >= 0) {
                mp[nums[i - k + 1]]--;
                sum -= nums[i - k + 1];
                if (mp[nums[i - k + 1]] == 0)
                    diffcnt--;
            }
        }
        return res;
    }
};

2461. 长度为 K 子数组中的最大和 1553

题意: 给一个整数数组,一个k,找出:1. 子数组长度为k 2. 所有元素各不相同。 返回满足条件的最大子数组和。不存在返回0.

code
class Solution {
public:
    long long maximumSubarraySum(vector<int>& nums, int k) {
        int n = nums.size();
        long long res = 0, sum = 0;
        int uniq = 0;
        unordered_map<int, int> mp;
        for (int i = 0; i < n; i++) {
            sum += nums[i];
            mp[nums[i]]++;
            if (mp[nums[i]] == 1)
                uniq++;

            if (i - k + 1 >= 0) {
                if (uniq == k)
                    res = max(res, sum);

                mp[nums[i - k + 1]]--;
                if (mp[nums[i - k + 1]] == 0)
                    uniq--;
                sum -= nums[i - k + 1];
            }
        }
        return res;
    }
};

1423. 可获得的最大点数 1574

题意:一个数组carPoints,每次可以从开头/末尾拿1张牌,最终必须正好拿k张。
返回可以获得的最大点数.

反向考虑 n-k 的min 值。这里如果按照之前模版要特判 n==k, 因此采用新模版做法。

code
class Solution {
public:
    int maxScore(vector<int>& cardPoints, int k) {
        int n = cardPoints.size();
        int m = n - k;
        int s = reduce(cardPoints.begin(), cardPoints.begin() + m);
        int min_s = s;
        for (int i = m; i < n; i++) {
            s += cardPoints[i] - cardPoints[i - m];
            min_s = min(s, min_s);
        }
        return reduce(cardPoints.begin(), cardPoints.end()) - min_s;
    }
};

1052. 爱生气的书店老板 1418

题意:书店开了n分钟,每分钟有一些顾客进入。给一个长度为n的数组 customers, 其中customer[i]表示第i分钟开始时进入人数,所有这些顾客在第i分钟解释后离开。 在某些分钟内,老板会生气,如果在第i分钟生气,那么 grumpy[i]=1 否则 grumpy[i]=0. 生气时顾客会不满意,老板可以控制连续 minites分钟不生气,但只能用一次,求最多多少顾客能满意。

分析:等价于求 grumpy 的满足条件的子数组,子数组中 1 的个数小于 3, 要求子数组对应的customer和最大。
开始想复杂了, 写成了能控制连续 minutes 不生气。

code
class Solution {
public:
    int maxSatisfied(vector<int>& customers, vector<int>& grumpy, int minutes) {
        int n = customers.size();
        int res = 0, sum = 0;
        for (int i = 0; i < n; i++) {
            sum += (grumpy[i] == 1 ? 0 : customers[i]);
        }
        int savedCustomers = 0;
        for (int i = 0; i < n; i++) {
            if (grumpy[i] == 1) {
                savedCustomers += customers[i];
            }
            res = max(res, sum + savedCustomers);
            if (i - minutes + 1 >= 0 && grumpy[i - minutes + 1])
                savedCustomers -= customers[i - minutes + 1];
        }

        return res;
    }
};

3679. 使库存平衡的最少丢弃次数 1639

题意:给两个整数 w 和 m, 以及一个整数数组 arrivals, 其中arrivals[i] 表示第 i 天到达的物品类型。遵循以下规则:

  1. 对于每个到达的物品可以保留或丢弃, 物品只能在到达当天被丢弃。
  2. 对于每一天i,考虑天数范围为 [max(1, i-w+1), i] (也就是直到第i天为止最近w天)
    1. 对于任何这样的窗口,保留的物品中每种最多只能出现 m 次。
    2. 如果在第i 天保留该到达物品会导致其类型在该窗口中出现次数超过m次,那么必须丢弃。
  3. 返回满足每个 w 天窗口中每种类型最多出现 m 次,最少要丢弃物品的数量。

题意好绕。维护一个长度为w的窗口,其中重复的不超过m次. 这题怎么做转换呢?读题漏了个点,一个物品只有当天知道是否要丢。那么当一个物品进入后,如果超过了m,那么要么直接丢弃这个,要么时间回溯到上一个出现的日期,把上一个丢弃。 这里可以贪心认为晚丢会更好,因为这样会让窗口中的个数比早丢更少,后面丢弃的物品数更少。 (窗口移动过程中如果保留了更晚到的,那么这个x在窗口中停留的时间更久了)

code
class Solution {
public:
    int minArrivalsToDiscard(vector<int>& arrivals, int w, int m) {
        int n = arrivals.size();
        int res = 0;
        unordered_map<int, int> cnt;
        for (int i = 0; i < n; i++) {
            if (cnt[arrivals[i]] == m) {                
                arrivals[i] = -1;
                res++;
            } else {
                cnt[arrivals[i]]++;
            }
            if (i - w + 1 >= 0)
                cnt[arrivals[i - w + 1]]--;
        }

        return res;
    }
};

3439. 重新安排会议得到最多空余时间 I 1729

题意:一个整数 evenTime 表示一个活动时长,开始于t = 0 , 结束于 t = eventTime.
给两个长度为 n 的整数数组 startTime 和 endTime, 表示n 个时间没有重叠的回忆, 其中第i个会议时间为[start[i], end[i]]
你可以重新安排最多 k 个会议, 规则是将会议时间平移,且会保留原来的时长,目标是移动后会议最大化相邻会议之间的最长连续空余时间。
移动后会议之间相对顺序保持不变。互不重叠。 返回重新安排可以得到的最大空余时间。

注意最多安排k个会议。那么就是说有 n-k 个 的时间窗口是不动的。如果没有k的上限,那么显然就是总时长-会议时长。
问题可以转化成 k 次操作,每次操作可以合并两个空闲时间段, k 次可以合并连续k+1 个空闲时间段。求最大长度。

注意是选k+1个而不是k个。

code
class Solution {
public:
    int maxFreeTime(int eventTime, int k, vector<int>& startTime,
                    vector<int>& endTime) {
        int n = startTime.size();
        int res = 0;
        // first  startTime[0]
        vector<int> free_slot(n + 1);
        free_slot[0] = startTime[0];
        for (int i = 1; i < n; i++)
            free_slot[i] = startTime[i] - endTime[i - 1];
        free_slot[n] = eventTime - endTime[n - 1];
        for(int i =0 ;i<=n;i++) cout<<free_slot[i]<<" "; cout<<endl;
        int sum = 0;
        for (int i = 0; i <= n; i++) {
            sum += free_slot[i];
            res = max(sum, res);
            if (i - k  >= 0) {
                sum -= free_slot[i - k];
            }
        }
        return res;
    }
};

3694. 删除子字符串后不同的终点 1739

题意:一个由自负 U D L R 组成的字符串,在无限的二维笛卡尔网格上移动
还有一个正整数 K , 必须选择移除恰好一个长为k 的连续子字符串s ,然后从0,0 还是执行剩余移动。
返回可到达的不同坐标的数量

分析:同样的模版题,区间内的操作计算一次位置集合即可。

code
class Solution {
public:
    int distinctPoints(string s, int k) {
        int res = 0;
        map<pair<int, int>, int> mp;
        int x = 0, y = 0;
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == 'U')
                y++;
            else if (s[i] == 'D')
                y--;
            else if (s[i] == 'L')
                x--;
            else
                x++;
            if (i - k + 1 >= 0 && !mp[{x, y}]) {
                res++;
                mp[{x, y}]++;
            }

            if (i - k + 1 >= 0) {
                if (s[i - k + 1] == 'U')
                    y--;
                else if (s[i - k + 1] == 'D')
                    y++;
                else if (s[i - k + 1] == 'L')
                    x++;
                else if (s[i - k + 1] == 'R')
                    x--;
            }
        }

        return max(res, 1);
    }
};

2134. 最少交换次数来组合所有的 1 II 1748

题意:交换定位选中一个数组中两个互不相同的位置并交换两者的值。 环形数组是一个数组,认为第一个元素和最后一个元素相邻。给一个二进制环形数组nums,返回在任意位置将数组中所有1聚集在一起的最少交换次数。

分析: 假设 0 有k个,最终肯定是有一个长度为k 窗口,里面都是0 , 那么就是找到 长为 k 的窗口中 0 最多的个数。 k减去 num_0就得到要移走的1 的个数。

踩坑: 对 0 的情况进行了特判。

code
class Solution {
public:
    int minSwaps(vector<int>& nums) {
        int n = nums.size();
        int res = 0, zero = 0;
        for (int i = 0; i < n; i++) {
            if (nums[i] == 0)
                zero++;
        }
        if (zero == 0)
            return 0;
        int cnt_1 = 0, min_1 = INT_MAX;
        for (int i = 0; i < n + zero; i++) {
            if (nums[i % n] == 1)
                cnt_1++;
            int l = (i - zero + 1) % n;
            if (l >= 0) {
                min_1 = min(min_1, cnt_1);
                if (nums[l] == 1)
                    cnt_1--;
            }
        }
        return min_1;
    }
};

1652. 拆炸弹 做到 O(n)

题意:有一个 长为 n 的循环数组 code 和一个密钥 k。
需要替换掉每一个数字,所有数字会同时替换。如果k > 0,将第 i 和数字和接下来 k 个数字之和替换。
如果k < 0 , 将第i个数字用之间的 k 个数字之和替换。 如果k =0, 将第i 个数字用0替换。
由于code 是循环的,返回解密后结果。

O(n) 解法。

code
class Solution {
public:
    vector<int> decrypt(vector<int>& code, int k) {
        int n = code.size();
        vector<int> res(n, 0);
        if (k == 0)
            return res;
        int sum = 0;
        if (k > 0) {
            for (int i = 0; i < n + k; i++) {
                sum += code[i % n];
                if (i - k >= 0) {
                    sum -= code[i - k];
                    res[i - k] = sum;
                }
            }
        } else {
            k *= -1;
            for (int i = 0; i < n + k; i++) {
                if (i - k >= 0) {
                    res[i % n] = sum;
                    sum -= code[i - k];
                }
                sum += code[i % n];
            }
        }
        return res;
    }
};

1297. 子串的最大出现次数 1748

题意:给一个字符串s,返回满足以下条件且出现次数 最大的 任意子串的 出现次数。

  1. 子串中不同字母数目必须小于等于 maxLetters
  2. 子串长度必须大于等于 minSize 且小于等于 maxSize

维护一个窗口 l,R 其中 窗口大小在 min-max之间。.. 脑筋急转弯,长度为minSize 的重复的肯定比更长的重复的更多。
因此只需要考虑长度为 minSize的子串即可。

code
class Solution {
public:
    int maxFreq(string s, int maxLetters, int minSize, int maxSize) {
        int res = 0, n = s.size();
        unordered_map<char, int> cnt;
        int l = 0, diffcnt = 0;
        map<string, int> scnt;
        for (int i = 0; i < n; i++) {
            cnt[s[i]]++;
            if (cnt[s[i]] == 1)
                diffcnt++;

            if (i - minSize + 1 >= 0) {
                if (diffcnt <= maxLetters) {
                    scnt[s.substr(i - minSize + 1, minSize)]++;
                    res = max(res, scnt[s.substr(i - minSize + 1, minSize)]);
                }
                cnt[s[i - minSize + 1]]--;
                if (cnt[s[i - minSize + 1]] == 0)
                    diffcnt--;
            }
        }
        return res;
    }
};

3652. 按策略买卖股票的最佳时机

题意:给两个整数数组 prices和strategy ,其中prices[i] 表示第i天股票价格,strategy[i]表示第i天的策略,其中-1表示买入,0表示持有,1表示卖出。 同时给一个偶数k, 可以对strategy有最多一次修改,包括:
选择 strategy恰好k 个连续元素。
将前 k/2 个元素 设为0。
将后 k/2 个元素设为1
利润定义:所有天数 strategy[i]*prices[i] (ps 这叫啥利润。。)
返回可能的最大利润

code
class Solution {
public:
    long long maxProfit(vector<int>& prices, vector<int>& strategy, int k) {
        int n = prices.size();
        long long res = 0, sum = 0, maxx = 0;
        for (int i = 0; i < n; i++)
            res += prices[i] * strategy[i];

        for (int i = 0; i < k / 2; i++) {
            sum += (-strategy[i]) * prices[i];
        }
        for (int i = k / 2; i < k; i++) {
            sum += (1 - strategy[i]) * prices[i];
        }
        maxx = max(maxx, sum);
        for (int i = k; i < n; i++) {
            sum += (1 - strategy[i]) * prices[i];
            sum -= (-strategy[i - k]) * prices[i - k];
            int middle = i - k / 2;
            sum -= prices[middle];
            maxx = max(maxx, sum);
        }

        return res + maxx;
    }
};

567. 字符串的排列

题意:给两个字符串s1 和s2 ,判断s2 是否包含s1 的序列,其中序列表示字符串的任意重排。 本身该题可以不用滑动窗口,但是用滑动窗口复杂度从O(26n)优化至 O(n),其中26为字符取值范围。

code
class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        vector<int> cnt(26,0);
        int diff = 0;
        int n1 = s1.size(), n2 = s2.size();
        if (n1 > n2)
            return false;
        for (int i = 0; i < n1; i++) {
            if (cnt[s1[i] - 'a'] == 0)
                diff++;
            cnt[s1[i] - 'a']++;
        }
        for (int i = 0; i < n2; i++) {
            cnt[s2[i] - 'a']--;
            if (cnt[s2[i] - 'a'] == 0)
                diff--;
            if (i < s1.size() - 1) {
                continue;
            }
            if (diff == 0)
                return true;

            if (cnt[s2[i - n1 + 1] - 'a'] == 0) {
                diff++;
            }
            cnt[s2[i - n1 + 1] - 'a']++;
        }
        return false;
    }
};

20260530 今天写了6题

438. 找到字符串中所有字母异位词

code
class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> res;
        int l1 = s.size(), l2 = p.size();
        if (l1 < l2)
            return res;
        vector<int> cnt(26, 0);
        int diff = 0;
        for (int i = 0; i < l2; i++) {
            if (cnt[p[i] - 'a'] == 0)
                diff++;
            cnt[p[i] - 'a']++;
        }
        for (int i = 0; i < l1; i++) {
            cnt[s[i] - 'a']--;
            if (cnt[s[i] - 'a'] == 0)
                diff--;
            if (i < l2 - 1)
                continue;
            if (diff == 0){
                res.push_back(i - l2 + 1);
            }
            if (cnt[s[i - l2 + 1] - 'a'] == 0) {
                diff++;
            }
            cnt[s[i - l2 + 1] - 'a']++;
        }
        return res;
    }
};

30. 串联所有单词的子串

题意:给一个字符串s 和一个字符串数组 words, words中所有字符串长度相同。
定义s 的串联子串 是指一个包含word始终所有字符串以任意顺序排列连接起来的子串。
返回所有串联子串在s中的开始索引。可以以任意顺序返回答案。

分析:注意到words 的长度在 5000 , s.length在 1e4以内。 直接想到的暴力解,观察到words中所有字符串长度相同 。如果存在匹配的子串,那么 区间长度 k 为sum words ,首先要满足字符个数是一致的, 但是问题在于怎么保证每三个的顺序是一样的。 可以想到用map 记录hash值?由于长度是固定不变的,但是窗口在移动时,所有hash值都会变。这样算法好像是O(n2)的。
其实 s 也可以按照固定长度进行单词划分,只是需要确定开始的下标i, 其中 i in [0,n-1] .剩余的就是套路,只是把单个字符变成了 单词。

先看了下题解灵神的实现,只能说题解写的很清晰 妙啊。 下面自己按照思路进行实现。

code
class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        vector<int> res;
        int wordLen = words[0].size();
        int totalLen = words.size() * wordLen;
        unordered_map<string, int> targetCnt;
        for (int i = 0; i < words.size(); i++) {
            targetCnt[words[i]]++;
        }
        // 枚举开始的左端点
        for (int start = 0; start < wordLen; start++) {
            unordered_map<string, int> cnt;
            int diff_word = 0;
            // 枚举单词右端点,滑窗
            for (int right = start + wordLen; right <= s.size();
                 right += wordLen) {
                // enter
                string word = s.substr(right - wordLen, wordLen);
                if (targetCnt[word] == cnt[word])
                    diff_word++;
                cnt[word]++;
                // skip
                if (right - totalLen < 0)
                    continue;
                // update
                if (diff_word == 0)
                    res.push_back(right - totalLen);
                // out
                word = s.substr(right - totalLen, wordLen);
                cnt[word]--;
                if (cnt[word] == targetCnt[word])
                    diff_word--;
            }
        }

        return res;
    }
};

1888. 使二进制字符串字符交替的最少反转次数 2006

题意: 给一个二进制字符串s, 可以任意顺序执行以下两种操作任意次。

  1. 删除字符串s的第一个字符并将它添加到字符串结尾
  2. 选择s中任意一个字符并将该字符反转,也就是如果值为0变成1,1变0.
    返回使s 变成交替字符串的前提下,类型2的最少操作次数。

分析:操作1 等价循环数组。
比如 1110 1110 也就是从 0,2n-1 的区间中找一个长度为n 的区间,要求区间内必须是交替的,但是要枚举一下开始时是0/1。 维护区间长度为n的最小交换次数即可。

开始我的思路是枚举开头是0 还是1 , 然后每种情况下维护窗口n,入时和current 判断是否要改,出时根据记录值统计是否修改过, 有点麻烦。
题解思路更巧妙一些,要么改成0101...,int(t[i])=imod2。 要么 1010... 也就是int(t[i])=imod2
把满足的视为 . 不满足的视为 x那么就是 X.XX.XX.XX
这个证明在周赛时候推出来还是挺绕的。。

code
class Solution {
public:
    int minFlips(string s) {
        int n = s.size();
        int res = n;
        int cnt = 0;

        for (int i = 0; i < 2 * n - 1; i++) {
            if (s[i % n] % 2 != i % 2)
                cnt++;

            if (i - n + 1 < 0)
                continue;
            res = min({res, cnt, n - cnt});
            if (s[i - n + 1] % 2 != (i - n + 1) % 2)
                cnt--;
        }

        return res;
        
    }
};

2156 先搁置, 等取模部分知识补完后补这题。

2156. 查找给定哈希值的子串 2063

题意:给定整数p和m,一个长度为k 且下标从0开始的字符串s的哈希值
hash(s, p, m) = (val(s[0]) * p0 + val(s[1]) * p1 + ... + val(s[k-1]) * pk-1) mod m
其中 val(s[i]) 表示 s[i] 在字母表中的下标,从 val('a') = 1 到 val('z') = 26 。

给你一个字符串 s 和整数 power,modulo,k 和 hashValue 。请你返回 s 中 第一个 长度为 k 的 子串 sub ,满足 hash(sub, power, modulo) == hashValue 。

测试数据保证一定 存在 至少一个这样的子串。

子串 定义为一个字符串中连续非空字符组成的序列。

分析:p^k % m 应该是个循环的? 哦哦应该是不用,维护一个左端点%m 的 p 即可,每次都少一个 p%m

2953 也暂时搁置,貌似是分组循环部分的题

2953. 统计完全子字符串 2449

posted on 2026-05-28 20:55  Eura42  阅读(8)  评论(0)    收藏  举报