时间限制:1秒
空间限制:32768K
给出一个正整数n,我们把1..n在k进制下的表示连起来记为s(n,k),例如s(16,16)=123456789ABCDEF10, s(5,2)=11011100101。现在对于给定的n和字符串t,我们想知道是否存在一个k(2 ≤ k ≤ 16),使得t是s(n,k)的子串。
输入描述:
第一行一个整数n(1 ≤ n ≤ 50,000)。
第二行一个字符串t(长度 ≤ 1,000,000)
输出描述:
“yes”表示存在满足条件的k,否则输出”no”
输入例子:
8
01112
输出例子:
yes
解法:直接暴力拆分然后做一个KMP,但是要注意用下标为1的KMP在串是空串的时候要GG.所以选择下标为0的KMP的写法。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3000010;
char s1[maxn], s2[maxn];
string s;
int fail[maxn];
int n,len1,len2;
int KMP()
{
int i=0, j=0;
while(i<len1){
if(j==-1||s1[i]==s2[j]){
i++;
j++;
}
else{
j=fail[j];
}
if(j==len2) return 1;
}
return 0;
}
int main()
{
scanf("%d",&n);
scanf("%s", s2);
len2 = strlen(s2);
int i=0, j=-1;
fail[0]=-1;
while(i<len2){
if(j==-1||s2[i]==s2[j]){
i++;
j++;
fail[i]=j;
}
else j=fail[j];
}
int ans = 0;
for(int jz = 2; jz<=16; jz++){
len1 = 0;
for(int i=1; i<=n; i++){
int x = i, cnt = 0, num[100];
while(x){
num[cnt++] = x%jz;
x/=jz;
}
for(int j=cnt-1; j>=0; j--){
if(num[j]<10){
s1[len1++]=num[j]+'0';
}
else{
s1[len1++]=num[j]-10+'A';
}
}
}
ans = max(ans, KMP());
if(ans > 0) break;
}
if(ans > 0) puts("yes");
else puts("no");
return 0;
}