Number of Beautiful Partitions
Number of Beautiful Partitions
You are given a string s that consists of the digits '1' to '9' and two integers k and minLength.
A partition of s is called beautiful if:
- s is partitioned into k non-intersecting substrings.
- Each substring has a length of at least minLength .
- Each substring starts with a prime digit and ends with a non-prime digit. Prime digits are '2' , '3' , '5' , and '7' , and the rest of the digits are non-prime.
Return the number of beautiful partitions of s . Since the answer may be very large, return it modulo .
A substring is a contiguous sequence of characters within a string.
Example 1:
Input: s = "23542185131", k = 3, minLength = 2 Output: 3 Explanation: There exists three ways to create a beautiful partition: "2354 | 218 | 5131" "2354 | 21851 | 31" "2354218 | 51 | 31"
Example 2:
Input: s = "23542185131", k = 3, minLength = 3 Output: 1 Explanation: There exists one way to create a beautiful partition: "2354 | 218 | 5131".
Example 3:
Input: s = "3312958", k = 3, minLength = 1 Output: 1 Explanation: There exists one way to create a beautiful partition: "331 | 29 | 58".
Constraints:
s consists of the digits '1' to '9' .
解题思路
这题很容易想到动态规划,不过如果直接暴力dp的话会超时,因此还需要进行优化,比赛的时候调了个多小时都没有调出来,说白了就是不熟练。
定义状态表示所有从前字符中分成组的合法方案的数量。状态转移方程就是其中要保证不为质数,并且要为质数。是第组的左端点,是第组的右端点。
因此就很容易写出TLE代码,时间复杂度为。
1 class Solution { 2 public: 3 int mod = 1e9 + 7; 4 5 int beautifulPartitions(string s, int k, int minLength) { 6 int n = s.size(); 7 vector<vector<int>> f(n + 1, vector<int>(k + 1)); 8 f[0][0] = 1; 9 unordered_set<int> st({2, 3, 5, 7}); 10 for (int i = 1; i <= n; i++) { 11 if (!st.count(s[i - 1] - '0')) { 12 for (int j = 1; j <= k; j++) { 13 for (int u = minLength * (j - 1) + 1; u + minLength - 1 <= i; u++) { 14 if (st.count(s[u - 1] - '0')) f[i][j] = (f[i][j] + f[u - 1][j - 1]) % mod; 15 } 16 } 17 } 18 } 19 return f[n][k]; 20 } 21 };
现在就要对其进行优化,对于第个循环,可以发现如果我们固定不变,而每次增加,那么的枚举范围的左端点总是固定不变的,而右端点每次会加,这意味着我们总是重复枚举前面的固定不变的部分,因此我们可以考虑开个变量来累加前面固定的部分,这样就不用每次从头开始枚举了。当时比赛就是卡在所要累加的值。其实看状态转移方程就可以发现,每次都是加上,而第一维是变化的量,对比于,当枚举到时就只多加了一个。因此当枚举到,就累加就可以了(前提是为质数)。关键是要看到前后两次是哪个量发生了变化。
AC代码如下,时间复杂度为:
1 class Solution { 2 public: 3 int mod = 1e9 + 7; 4 5 int beautifulPartitions(string s, int k, int minLength) { 6 int n = s.size(); 7 vector<vector<int>> f(n + 1, vector<int>(k + 1)); 8 f[0][0] = 1; 9 unordered_set<int> st({2, 3, 5, 7}); 10 for (int j = 1; j <= k; j++) { 11 int cnt = 0; 12 for (int i = minLength * j; i <= n; i++) { 13 if (st.count(s[i - minLength] - '0')) cnt = (cnt + f[i - minLength][j - 1]) % mod; 14 if (!st.count(s[i - 1] - '0')) f[i][j] = cnt; 15 } 16 } 17 return f[n][k]; 18 } 19 };
当然,可以改变和的枚举顺序,这里就定义表示所有从前字符中分成组的合法方案的数量(和上面的定义一样),这种写法会比上面的快一些(涉及到底层)。
AC代码如下:
1 class Solution { 2 public: 3 int mod = 1e9 + 7; 4 5 int beautifulPartitions(string s, int k, int minLength) { 6 int n = s.size(); 7 vector<vector<int>> f(k + 1, vector<int>(n + 1)); 8 f[0][0] = 1; 9 unordered_set<int> st({2, 3, 5, 7}); 10 for (int j = 1; j <= k; j++) { 11 int cnt = 0; 12 for (int i = minLength * j; i <= n; i++) { 13 if (st.count(s[i - minLength] - '0')) cnt = (cnt + f[j - 1][i - minLength]) % mod; 14 if (!st.count(s[i - 1] - '0')) f[j][i] = cnt; 15 } 16 } 17 return f[k][n]; 18 } 19 };
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16908636.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效