百度之星:度度熊剪纸条 HDU - 6376(思维+情况分类)

传送门

题解:

第一种情况:如果k = 0,那么直接输出前缀1数量   如果字符串全为1,那么直接输出n

第二种i情况;如果没有上述情况,则统计1的数量 

统计前缀1的数量为a

统计后缀1的数量为b(前缀和后缀不可能重合,因为如果重合,就说明整个串全为1,这和预判断矛盾)

统计中间的1的数量,放入num数组

几种需要注意的情况 

1、因为前缀1不需要剪就已经在前缀,如果要它,就不用花钱。(注意这里是如果要,也可以不要,如5 1 10110 输出2)【自然前缀1】

2、如果没有前缀1,那么剪第一个前缀1的时候,只需要花费1块钱,如9 5 011001010,输出4,只需要把前面的【0】11001010的【0】剪掉,然后把后面两个1单独剪出来,后面的00不用管它,然后直接把放在后面就可以了,因为只管前缀嘛,但是这种只花费1块钱的,只能有一个,(相当于人为把前面的0减掉,获取具有直接前缀1的情况)。【人工前缀1】

3、如果要后缀1,那么后缀1也只需要花费1块钱,如5 1 10001,输出2

综合上面的几种情况,进行分类讨论

注意上述1和2是互斥的!

要前缀1(不花钱),要后缀1(花1块钱),ans += a + b, 剩下的钱除以2得到m,将num从大到小排序,ans加上前m项。

要前缀1(不花钱),不要后缀1(不花钱),ans += a,剩下的钱除以2得到m,将num从大到小排序,ans加上前m项。

判断下中间是否有连续的1,有:(1).不要前缀1(不花钱),要人工前缀1(因为人工前缀1只需要1刀,而其他的中间的1需要2刀,那么我们可以在所有的中间1中,找到最大的那个,作为第一刀切下去的地方,制造仍前缀1,那么只需要花1块钱即可,不需要花2块钱,相当于k+1,所以要人工前缀1的话,就k++),不要后缀1(不花钱),剩下的钱除以2得到m,将num从大到小排序,ans加上前m项。

(2).不要前缀1(不花钱),要人工前缀1(k++),要后缀1(花1块钱),ans += b, 剩下的钱除以2得到m,将num从大到小排序,ans加上前m项。 【注意】这里后缀1会不会和人工前缀1重合呢?如0011,这里11既可以当人工前缀1,也可以当后缀1,k到底是+1呢,还是-1呢?怎么解决?其实我们可以直接把这种人工前缀1和后缀1重合德情况排除在这里之外,单独解决。那么这里就需要num数组中一定要具有中间1才可以。

中间没有连续的1,如果没有中间1,那么就花1块钱要后缀1 (至少有1块钱,因为没有钱的情况已经预处理过了),ans = b。

把上面的情况分别处理一下,记录最大的ans,输出即可。

附上代码:


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

const int INF=0x3f3f3f3f;
const int maxn = 10005;

using namespace std;

int n, k, num[maxn];
char s[maxn];

int main()
{
    while(~scanf("%d%d", &n, &k)){
        memset(num, 0, sizeof(num));
        scanf("%s", s);
        int a = 0, bg = 0, b = 0, ed = n - 1;
        while(bg < n && s[bg] == '1'){//前缀1
            a++;
            bg++;
        }
        if(bg == n || k == 0){
            printf("%d\n", a);
            continue ;
        }
        while(ed >= 0 && s[ed] == '1'){//后缀1
            b++;
            ed--;
        }
        int cnt = 0, flag = 0;
        for(int i = bg; i <= ed; i++){
            if(s[i] == '1'){
                num[cnt]++;
                flag = 1;
            }else if(flag && s[i] == '0'){
                cnt++;
                flag = 0;
            }
        }
        sort(num, num + cnt, greater<int>());
        int ans = 0;
        //要前缀1
        if(a != 0){
            int mon, cns;
            if(b != 0){
                mon = (k - 1) / 2;
                cns = a + b;
                for(int i = 0; i < mon; i++)
                    cns += num[i];
                ans = max(ans, cns);
            }
            mon = k / 2;
            cns = a;
            for(int i = 0; i < mon; i++)
                cns += num[i];
            ans = max(ans, cns);
        }
        //不要前缀1
        if(cnt){
            int mon, cns;
            if(b != 0){
                mon = (k + 1 - 1) / 2;
                cns = b;
                for(int i = 0; i < mon; i++)
                    cns += num[i];
                ans = max(ans, cns);
            }
            mon = (k + 1) / 2;
            cns = 0;
            for(int i = 0; i < mon; i++)
                cns += num[i];
            ans = max(ans, cns);
        }else{
           ans = max(ans, b);
        }
        printf("%d\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhouzi2018/article/details/81630686