【思维】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;
}