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_2le 10^6)
首先,([s_2,n_2])我们是不能直接求出来的
但是很明显([[s_2,n_2],m] = [s_2,n_2m])
所以现在我们只需要求最大的(m')使得([s_2, m'])为([s_1,n_1])的子序列
那么就有
[m = leftlfloor{frac{m'}{n_2}}
ight
floor
]
我们发现,直接求(m')是不容易实现的,因为他的上界很大,可能到达$frac{|s_1| imes 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
",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
",i,sum);
ans = max(ans,sum);
}
return ans / n2;
}
};