子串-NC13253
描述
给出一个正整数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
思路:
处理数字转化为2~16进制组成字符串
用kmp预处理并找寻子串
(也可以用string的find函数)
#include<bits/stdc++.h>
#include<time.h>
#include<cctype>
#include<iostream>
#include<ostream>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<string>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;//1061109567
const int INF=0x7fffffff;//2147483647
const int SUP=0x80000000;//-2147483648
#define MAX 1000005
using namespace std;
int nex[MAX];
string trans(int n,int k)//转换该进制下数字从1到n并组成字符串
{
string s;
for(int i=n;i>=1;i--)
{
int j=i;
while(j)
{
if(j%k>9)//超过10
s+=j%k-10+'A';
else s+=j%k+'0';
j/=k;
}
}
reverse(s.begin(),s.end());
return s;
}
int solve(string s,string t)//kmp解决
{
memset(nex,-1,sizeof(nex));
int en=t.size();
for(int i=1;i<en;i++)
{
int j=nex[i-1];
while((t[j+1]!=t[i])&&(j>=0))
j=nex[j];
if(t[j+1]==t[i])
nex[i]=j+1;
else
nex[i]=-1;
}
int i=0,j=0;
int len=s.size();
while(i<len)
{
if(s[i]==t[j])
{
i++;j++;
if(j==en)return 1;
}
else
{
if(j==0)i++;
else j=nex[j-1]+1;
}
}
return 0;
}
int main()
{
int n,k;
string t,s;
cin>>n>>t;
for(k=2;k<=16;k++)//例举所有进制
{
s=trans(n,k);
//cout<<s<<" "<<k<<endl;
if(solve(s,t))
{cout<<"yes";break;}
}
if(k==17)cout<<"no";
cout<<endl;
return 0;
}