题目大意:
给你两个字符串p和s,让你求出一个字典序尽量小的长度为k的01串密钥,能将p转化为s。
密钥的工作方式如下:
第i位是0,表示这一位无用;
第i位是1,表示这一位有用。
若密钥的长度比s短,则可以通过循环的方式补齐。
思路:
由于密钥的长度为固定的k,我们可以先预处理出k个字符串p1,其中p1[i]是p中所有位置在mod k意义下为i的字符所构成的串。
接下来我们枚举密钥中出现的1的个数,对应的是密钥循环的周期长度。
每次还要处理出字符串s对应的s1。
然后从后往前贪心,枚举p1中的每个字符串p1[i]和s1中的每个字符串s1[p],如果p1[i]==s1[p]那么这一位可以是1。
由于是从后往前贪心,在这里选1肯定是相对更优的。
然后对于不同的1的个数,我们都可以找出一个字典序最小的密钥tmp,最后再找出其中字典序最小的即可。
注意字符串中可能会有空格和一堆奇怪的字符,所以必须得getline。
1 #include<string> 2 #include<iostream> 3 #include<algorithm> 4 const int K=2001; 5 int k,p_len,s_len; 6 std::string p,s,p1[K],s1[K],ans; 7 int main() { 8 std::ios_base::sync_with_stdio(false); 9 std::cin.tie(NULL); 10 std::getline(std::cin,p); 11 std::getline(std::cin,s); 12 std::cin>>k; 13 p_len=p.length(),s_len=s.length(); 14 for(register int i=0;i<p_len;i++) { 15 p1[i%k]+=p[i]; 16 } 17 ans="2"; 18 int max_period=std::min(k,s_len); 19 for(register int i=1;i<=max_period;i++) { 20 for(register int j=0;j<i;j++) { 21 s1[j]=""; 22 } 23 for(register int j=0;j<s_len;j++) { 24 s1[j%i]+=s[j]; 25 } 26 std::string tmp; 27 int p=i-1; 28 for(register int i=k-1;i>=0;i--) { 29 if(p>=0&&p1[i]==s1[p]) { 30 p--; 31 tmp+="1"; 32 } else { 33 tmp+="0"; 34 } 35 } 36 if(p<0) { 37 std::reverse(tmp.begin(),tmp.end()); 38 ans=std::min(ans,tmp); 39 } 40 } 41 if(ans=="2") ans="0"; 42 std::cout<<ans<<std::endl; 43 return 0; 44 }