Codeforces Round #575 (Div. 3) D2. RGB Substring (hard version)
题意:
给你一个长为n的仅由'R','G','B'构成的字符串s,你需要在其中找出来一个子串。使得这个子串在“RGBRGBRGBRGB........(以RGB为循环节,我们称这个串为str)”里面也是一个子串,这个子串的长度是k
可是有可能s字符串中找不到,那么这个时候就可以改变s字符串中某些位置的字母来完成任务。问最少需要改变多少个字母
题解:
主要看暴力的姿势对不对。在上一道的D1上面,我是对s字符串的每一个位置进行‘R’,‘G’,‘B’的枚举,因为如果这个子串也是str的子串的话,那么肯定是以‘GB’,‘B’,“RGB”这三个为开头后面都是RGB
1 if(s[i]!='G') sum++;//,printf("1\n"); 2 if(s[i+1]!='B') sum++;//,printf("2\n"); 3 for(int k=0,j=i+2; j<i+m; ++j,k++,k%=3) 4 //因为str字符串是以RGB循环,所以k就是来表示现在是R、G、B中的谁 5 6 if(s[i]!='B') sum++;//,printf("6\n"); 7 //if(s[i+1]!='B') sum++; 8 for(int k=0,j=i+1; j<i+m; ++j,k++,k%=3) 9 10 11 12 //if(s[i]!='B') sum++,printf("6\n"); 13 //if(s[i+1]!='B') sum++; 14 for(int k=0,j=i; j<i+m; ++j,k++,k%=3)
就是这样先枚举字符串s的每一个位置,再枚举开头的第一个字母(‘R’、‘G’、‘B’)
但是T了 T_T
T代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<map> 6 #include<math.h> 7 using namespace std; 8 typedef long long ll; 9 const int maxn=2e5+5; 10 const int mod=26; 11 const int INF=0x3f3f3f3f; 12 const int block=300; 13 char s[maxn]; 14 int main() 15 { 16 int t; 17 scanf("%d",&t); 18 while(t--) 19 { 20 int n,m,ans=INF,sum; 21 scanf("%d%d",&n,&m); 22 scanf("%s",s); 23 if(m==1) 24 { 25 printf("0\n"); 26 continue; 27 } 28 for(int i=0; i<n; ++i) 29 { 30 if(i+m<=n) 31 { 32 sum=0; 33 if(s[i]!='G') sum++;//,printf("1\n"); 34 if(s[i+1]!='B') sum++;//,printf("2\n"); 35 for(int k=0,j=i+2; j<i+m; ++j,k++,k%=3) 36 { 37 if(k==0) 38 { 39 if(s[j]!='R') ++sum;//,printf("3\n"); 40 } 41 else if(k==1) 42 { 43 if(s[j]!='G') ++sum;//,printf("4\n"); 44 } 45 else if(k==2) 46 { 47 if(s[j]!='B') ++sum;//,printf("5\n"); 48 } 49 } 50 ans=min(sum,ans); 51 sum=0; 52 if(s[i]!='B') sum++;//,printf("6\n"); 53 //if(s[i+1]!='B') sum++; 54 for(int k=0,j=i+1; j<i+m; ++j,k++,k%=3) 55 { 56 if(k==0) 57 { 58 if(s[j]!='R') ++sum;//,printf("7\n"); 59 } 60 else if(k==1) 61 { 62 if(s[j]!='G') ++sum;//,printf("8\n"); 63 } 64 else if(k==2) 65 { 66 if(s[j]!='B') ++sum;//,printf("9\n"); 67 } 68 } 69 ans=min(sum,ans); 70 //printf("%d %d\n",sum,i); 71 sum=0; 72 //if(s[i]!='B') sum++,printf("6\n"); 73 //if(s[i+1]!='B') sum++; 74 for(int k=0,j=i; j<i+m; ++j,k++,k%=3) 75 { 76 if(k==0) 77 { 78 if(s[j]!='R') ++sum;//,printf("77\n"); 79 } 80 else if(k==1) 81 { 82 if(s[j]!='G') ++sum;//,printf("88\n"); 83 } 84 else if(k==2) 85 { 86 if(s[j]!='B') ++sum;//,printf("99\n"); 87 } 88 } 89 ans=min(sum,ans); 90 } 91 else 92 { 93 break; 94 } 95 } 96 printf("%d\n",ans); 97 } 98 return 0; 99 }
除了这样外,还可以先枚举k(开头第一个字母),然后再枚举每一个字符串s的位置
这样也把所有情况包含了,具体看代码
代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<map> 6 #include<math.h> 7 using namespace std; 8 typedef long long ll; 9 const int maxn=2e5+5; 10 const int mod=26; 11 const int INF=0x3f3f3f3f; 12 const int block=300; 13 char s[maxn],num[maxn]; 14 int check(int status,int position) //就是看一下这个位置匹配成不成功,需不需要改变这个位置的字符 15 { 16 if(status==0 && s[position]=='R') 17 return 0; 18 else if(status==1 && s[position]=='G') 19 return 0; 20 else if(status==2 && s[position]=='B') 21 return 0; 22 return 1; 23 } 24 int main() 25 { 26 int t; 27 scanf("%d",&t); 28 while(t--) 29 { 30 int n,m,ans=INF,sum; 31 scanf("%d%d",&n,&m); 32 scanf("%s",s); 33 if(m==1) 34 { 35 printf("0\n"); 36 continue; 37 } 38 for(int status=0;status<3;++status) //枚举开头第一个字母 39 { 40 sum=0; 41 memset(num,0,sizeof(num)); 42 for(int i=1;i<=n;++i) //这里和上一个TLE的代码不一样,这里是枚举到了n 43 { //只有这样在status变化的时候才会把所有情况包含,可以实践一下! 44 num[i]=check((status+i-1)%3,i-1); 45 sum+=num[i]; 46 if(i>=m) 47 sum-=num[i-m]; 48 if(i>=m) 49 ans=min(ans,sum); 50 } 51 } 52 printf("%d\n",ans); 53 } 54 return 0; 55 }