可惜没如果=_=
时光的河入海流

题目链接在本地,题目大意是从一段只包含0,1,2 的字符串中选出若干个子序列“2020”,选出一个2020序列以后,这四个数字从原来的位置上删除,问最多能选出多少个这种序列。

一开始想的贪心思想是从左往右扫描,越靠左满足2020的越先选出来,后来发现了反例就是20202200,如果越靠左满足的越先选出来,那这个只能选出一个2020,但是我们可以先选左边的20,然后在后四个中取出一个20,另一个同理,因此这种贪心思想是错误的。

我们现在考虑另一种贪心思想,对于出现的2和0,我们一定把它当做第一个2和0,为什么这么做可以参考上面的反例。但是这个新的20不能全当新的,一定是到了一个数目为止,后面出现的20都作为第二个20,现在我们需要知道这个数是多少,这个步骤用二分做即可。

这题主要难想的是贪心的思想,一定要先满足前面的够用才能统计后面的20,不然就会出现反例中的情况。

 

 1 #include "bits/stdc++.h"
 2 using namespace std;
 3 const int MAX=1e5+5;
 4 int n,a[5];
 5 char s[MAX];
 6 bool feasible(int x){
 7     int i,j;
 8     a[1]=a[2]=a[3]=a[4]=0;
 9     for (i=1;i<=n;i++){
10         if (s[i]=='2'){
11             if (a[1]!=x) a[1]++;
12             else if (a[3]<a[2]) a[3]++;
13         }
14         if (s[i]=='0'){
15             if (a[2]!=x){
16                 if (a[2]<a[1]) a[2]++;
17             }
18             else{
19                 if (a[4]<a[3]) a[4]++;
20             }
21         }
22         if (a[4]==x) return true;
23     }
24     return false;
25 }
26                 
27 int main(){
28 //    freopen ("b.in","r",stdin);
29 //    freopen ("b.out","w",stdout);
30     int i,j,low,high,mid,ans;
31     while (scanf("%d",&n)!=EOF){
32         scanf("\n%s",s+1);
33         low=1,high=n;
34         ans=0;
35         while (low<=high){
36             mid=(low+high)>>1;
37             if (feasible(mid)){
38                 ans=mid;
39                 low=mid+1;
40             }
41             else high=mid-1;
42         }
43         printf("%d\n",ans);
44     }
45     return 0;
46 }

 

posted on 2022-07-07 20:56  珍珠鸟  阅读(28)  评论(0)    收藏  举报