倍增优化dp,P10976 统计重复个数

目录

一、题目

1、题目描述

2、输入输出

2.1输入

2.2输出

3、原题链接

二、解题报告

1、思路分析

2、复杂度

3、代码详解


一、题目

1、题目描述

2、输入输出

2.1输入
2.2输出

3、原题链接

https://www.luogu.com.cn/problem/P10976


二、解题报告

1、思路分析

注意到 \[s2, n2, m] = s2, m \* n2,所以如果我们可以计算出 s1, n1 最多可以得到多少个s2,不妨设为 ans 个,那么最大的 m 就是 floor(ans / m)

如何计算 ans?

如果我们定义 fi, j 为 从 i 开始,得到 j 个 s2 所需最少字符数的话,fi, j = f(i + \|s1\|) % \|s1\|, j - 1 + fi, 1

很经典的阶段性递推,我们考虑倍增加速这个过程:

定义 fi, j 为 从 i 开始,得到 2^j 个 s2 所需的最少字符数,那么 fi, j = fi, j - 1 + f(i + f\[i, j - 1) % |s1|, j - 1]

预处理完f\[\] 后,我们从 0 出发(从开头出发一定是最优的,因为从中间出发,计算所需字符数还是要加上跳过的字符),从高位到低位贪心的累加f\[\],即可得到ans

2、复杂度

时间复杂度: O(|s1||s2| + n1 log(n1 |s1| / |s2|))空间复杂度:O(|s1| + |s2| + n1 log(n1 |s1| / |s2|)

3、代码详解

复制代码
 ​
cpp 复制代码
#include <bits/stdc++.h>
namespace ranges = std::ranges;
namespace views = std::views;
using i64 = long long;
using u32 = unsigned;
using u64 = unsigned long long;

constexpr int B = 30;
constexpr int N = 100;

i64 dp[N][B];

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    std::string s1, s2;
    int n1, n2;
    while (std::cin >> s2 >> n2 >> s1 >> n1) {
        /*
        [[s2, n2], m] = [s2, m * n2]        
        */ 
        bool ok = true;
        for (int i = 0; i < s1.size(); ++i) {
            dp[i][0] = 0;
            int cur = i;
            for (int j = 0; j < s2.size(); ++j) {
                int c = 0;
                while (s1[cur] != s2[j]) {
                    if (++cur == s1.size()) cur = 0;
                    if (++c > s1.size()) {
                        ok = false;
                        break;
                    }
                }   
                if (!ok) break;
                if (++cur == s1.size()) cur = 0;
                dp[i][0] += c + 1;
            }
            if (!ok) break;
        }
        if (!ok) {
            std::cout << 0 << '\n';
            continue;
        }
        for (int j = 0; j + 1 < B; ++j) {
            for (int i = 0; i < s1.size(); ++i) {
                dp[i][j + 1] = dp[i][j] + dp[(i + dp[i][j]) % s1.size()][j];
            }
        }
        i64 ans = 0, tot = 0;
        for (int j = B - 1; j >= 0; --j) {
            if (tot + dp[tot % s1.size()][j] <= n1 * s1.size()) {
                tot += dp[tot % s1.size()][j];
                ans |= 1 << j;
            }
        }

        std::cout << ans / n2 << '\n';
    }

    return 0;
}
相关推荐
星轨初途26 分钟前
LeetCode 热题 100——day11 滑动窗口最大值
数据结构·c++·算法·leetcode·职场和发展
gbase_lmax1 小时前
深度递归与广度递归(DFS,BFS)实现
算法·深度优先·宽度优先
西柚研究生1234562 小时前
论文分析15:跨层特征交互的多尺度无人机小目标检测算法
人工智能·算法·目标检测
rannn_1119 小时前
【力扣hot100】链表专题|160、206、234、141、142
java·算法·leetcode·链表·面试·开发
数模竞赛Paid answer9 小时前
2026年华东杯数学建模B题医药物流安排问题解题全过程文档及程序
算法·数学建模·数据分析·华东杯
不会代码的小猴10 小时前
21. 泛型编程上
开发语言·c++·笔记·算法
AI备案指南-满满11 小时前
大模型与算法备案全流程详解:从零到通过的完整指南
人工智能·算法·备案·大模型备案·算法备案
江畔柳前堤11 小时前
LLM 训练核心机制深度解析:Warmup、Cosine Decay 与 Perplexity 的完整知识体系
网络·人工智能·深度学习·算法·机器学习·语音识别
一只旭宝11 小时前
细讲C加加【9】C++ std::function与std::bind详解|仿函数、绑定器、类成员绑定、占位符、成员偏移指针
开发语言·c++·算法
良木林11 小时前
子串 - LeetCode hot 100
算法·leetcode·职场和发展