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 }
View Code

 

除了这样外,还可以先枚举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 }
View Code

 

posted @ 2019-09-16 20:40  kongbursi  阅读(180)  评论(0编辑  收藏  举报