Leecoder466 Count The Repetitons
Leecoder466 Count The Repetitons
题目大意
定义\([s,n]\)为连续\(n\)个串\(s\)构成的串
现在给定\(s_1,n_1,s_2,n_2\),求最大的\(m\)满足\([[s_2,n_2],m]\)是\([s_1,n_1]\)的子序列
\(|s_1|,|s_2| \le 100,n_1,n_2\le 10^6\)
首先,\([s_2,n_2]\)我们是不能直接求出来的
但是很明显\([[s_2,n_2],m] = [s_2,n_2m]\)
所以现在我们只需要求最大的\(m'\)使得\([s_2, m']\)为\([s_1,n_1]\)的子序列
那么就有
\[m = \left\lfloor{\frac{m'}{n_2}}\right\rfloor
\]
我们发现,直接求\(m'\)是不容易实现的,因为他的上界很大,可能到达$\frac{|s_1| \times n_1}{n_2} $
考虑把\(m'\)二进制分解之后分位贪心
设\(f_{i,j}\)表示从\(s_1\)的第\(i\)位开始匹配\(2^j\)个\(s_2\)需要的字符个数
那么则有
\[f_{i,j} = f_{i,j - 1} + f_{(i + f_{i,j - 1}) \% |s_1|,j - 1}
\]
至于\(f_{i,0}\)我们可以使用最朴素的算法,直接暴力匹配,
注意判断无解的情况直接输出\(0\)就好了
这样我们就预处理完了
求答案就直接暴力枚举开头位置
然后利用倍增数组从高位向低位贪心,另外当前用了多少字符的初始值应该是\(i\)而不是\(0\)
class Solution {
int len1,len2;
char s1[505],s2[505];
long long f[31][505];
public:
int getMaxRepetitions(string S1, int n1, string S2, int n2) {
memset(f,0,sizeof(f));
len1 = S1.size();
len2 = S2.size();
for(int i = 0;i < len1;++i) s1[i] = S1[i];
for(int i = 0;i < len2;++i) s2[i] = S2[i];
// printf("%d %d\n",len1,len2);
for(int i = 0;i < len1;++i){
int pos = i;
for(int j = 0;j < len2;++j){
int cnt = 0;
while(s1[pos] != s2[j]){
pos = (pos + 1) % len1;
if(++cnt >= len1) return 0;
}
pos = (pos + 1) % len1;
f[0][i] += cnt + 1;
}
}
// for(int i = 0;i < len1;++i)printf("%d ",f[0][i]);puts("");
for(int j = 1;j <= 30;++j){
for(int i = 0;i < len1;++i){
f[j][i] = f[j - 1][i] + f[j - 1][(i + f[j - 1][i]) % len1];
}
}
long long ans = 0;
for(int i = 0;i < len1;++i){
long long t = i,sum = 0;
for(int j = 30;j >= 0;--j){
if((t + f[j][t % len1]) <= (len1) * n1){
t += f[j][t % len1];
sum += 1 << j;
}
}
//printf("%d %lld\n",i,sum);
ans = max(ans,sum);
}
return ans / n2;
}
};