link
题意
把一个字符串切割为k段, 每段至少长minLength, 且段以一个质数开始, 以非质数结束.
问切割方案. ( n<=2000)
定义f[i][j]f[i][j]f[i][j]表示把前iii个字符分为jjj段的方案
这样每次转移需要枚举一个qqq让[q+1,j][q+1,j][q+1,j]自成一段, 转移为
f[i][j]+=f[q][j−1]f[i][j] +=f[q][j-1]f[i][j]+=f[q][j−1]
复杂度为O(n3)O(n^3)O(n3), 不过这个转移显然是可以优化的.
观察这个转移, 符合条件的qqq是
q<=i−minLength&&s[q]∈[2,3,5,7]q<=i-minLength\ \ \&\&\ \ s[q]\in[2,3,5,7]q<=i−minLength && s[q]∈[2,3,5,7]
那么新开一个前缀和数组, pre[i][j]=∑q<=i&&s[q]∈[2,3,5,7]f[q][j]pre[i][j]=\sum\limits_{q<=i\&\&s[q]\in[2,3,5,7]} f[q][j]pre[i][j]=q<=i&&s[q]∈[2,3,5,7]∑f[q][j](这里s[q]s[q]s[q]表示第q+1q+1q+1个字符)
转移为(当s[i−1]s[i-1]s[i−1]不为质数时)
f[i][j]=pre[i−minLength][j−1]f[i][j] = pre[i-minLength][j-1]f[i][j]=pre[i−minLength][j−1]
然后其实这个preprepre数组很好维护. 因为根据转移, 用到的i−minLengthi-minLengthi−minLength是递增的
所以此时可以把pre[i−minLength][.....]pre[i-minLength][.....]pre[i−minLength][.....]的值视为已知, 转移为
pre[i][j−1]=pre[i−1][j−1]+f[i−minLength][j−1]pre[i][j-1] = pre[i-1][j-1]+f[i-minLength][j-1]pre[i][j−1]=pre[i−1][j−1]+f[i−minLength][j−1]
复杂度O(n2)O(n^2)O(n2)
class Solution {
public:static const int maxn = 2009;const int mod = 1e9+7;int pre[maxn][maxn],f[maxn][maxn];bool iszhi(char c){int x = c-'0';if( x!=2 && x!=3 && x!=5 && x!=7 )return false;return true;}int beautifulPartitions(string s, int k, int minLength) {/*f[i][j]表示前i个字符分为j段的方案从f[q][j-1]转移而来, 要求q+1是质数, j是非质数pre[x][j]表示q<=x, 且x+1为质数的f[q][j]和*/f[0][0] = 1;int n = s.size();for(int i=minLength;i<=n;i++){int zhi = iszhi( s[i-1] );int x = i-minLength;for(int j=1;j<=i;j++){if( x-1>=0 )pre[x][j-1] = pre[x-1][j-1];if( iszhi( s[i-minLength] ) )pre[x][j-1] = ( pre[x][j-1]+f[i-minLength][j-1] )%mod;if( !zhi )f[i][j] = pre[i-minLength][j-1]; // f[q][j-1]的和, 满足q+1为质数if( iszhi( s[i] ) ) pre[i+minLength][j] += f[i][j];}}return f[n][k];}
};
上一篇:嫩有什么成语有哪些
下一篇:形容闺蜜情深的成语有哪些