【思维】HDU 6376 度度熊剪纸条 【01串,剪k刀,问拼接后最多的前缀1数量是多少】

【思维】HDU 6376 度度熊剪纸条 【01串,剪k刀,问拼接后最多的前缀1数量是多少】

Problem Description
度度熊有一张纸条和一把剪刀。

纸条上依次写着 N 个数字,数字只可能是 0 或者 1。

度度熊想在纸条上剪 K 刀(每一刀只能剪在数字和数字之间),这样就形成了 K+1 段。

他再把这 K+1 段按一定的顺序重新拼起来。

不同的剪和接的方案,可能会得到不同的结果。

度度熊好奇的是,前缀 1 的数量最多能是多少。

Input
有多组数据,读到EOF结束。

对于每一组数据,第一行读入两个数 N 和 K 。

第二行有一个长度为 N 的字符串,依次表示初始时纸条上的 N 个数。

0 ≤ K < N ≤ 10000

所有数据 N 的总和不超过100000

Output
对于每一组数据,输出一个数,表示可能的最大前缀 1 的数量。

Sample Input
5 1
11010
5 2
11010

Sample Output
2
3

题意:

一个01字符串,可以剪k 刀,把它变成k + 1段,按照一定的顺序拼接起来,问可能的最大前缀1数量是多少?

思路:

  • 预先判断
    • 如果k = 0,那么直接输出前缀1数量
    • 如果字符串全为1,那么直接输出n
  • 如果没有上述情况,则统计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需要2刀,那么我们可以在所有的中间1中,找到最大的那个,作为第一刀切下去的地方,制造仍前缀1,那么只需要花1块钱即可,不需要花2块钱,相当于k+1,所以要人工前缀1的话,就k++),不要后缀1(不花钱),剩下的钱除以2得到m,将num从大到小排序,ans加上前m项。
    • 不要前缀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块钱,因为没有钱的情况已经预处理过了),ans = b。

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

AC代码

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <vector>
#include <queue>
#include <map>
#include <iterator>
#define INF 0x3f3f3f3f

using namespace std;

const int maxn = 10005;
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')
        {
            a++;
            bg++;
        }
        if(bg == n || k == 0)
        {
            printf("%d\n", a);
            continue ;
        }
        while(ed >= 0 && s[ed] == '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;
        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);
        }
        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);
        }
        ans = max(ans, b);
        printf("%d\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Floraqiu/article/details/81591799