题目链接:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=825&pid=1003
这道题真是挺(sang)不(xin)错(bing)的(kuang),我基本上这道题写了两个小时,wa了6次。精力都用过做这倒题了~~
首先,举个例子:
15 4
111011001111001
1:我们先吧这个分成这样:
1:111 0 2:11 3:00 4:1111 5:001
我们要最大效率的得到最大字串,可以单独减下来几个全部为1的字段,加在前面,然后接着是一个前缀为1的字段。剩下的放到后面。比如这道题可以组合为:
2 4 1 3 5
其中可以分为三部分,第一部分是2和4,第二部分是1,第三部分是3和5
其中第一部分全是1,第二部分前缀为1,第三部分随意。
最大前缀基本上就长这个样子。
经过以上分析,下面就应该确定如果找这三部分了。
其中我们先这样分割:
111 11 1111 1
要注意的一点是如果首尾都有0,那就把0放在首位,中间的0可以忽视,比如00110100应分为00 11 1 00
然后我们知道,第二部分取第一段不用切割,其他均需要切割一次。
第一部分不会在第一段取,然后如果取中间,需要两次切割,取尾部需要1次。
下面就很好解决了。我们先不考虑第一段和最后一段,先在中间取第一部分,留两次切割。
可以知道,2次切割可以切一段。
贪心取最大值1111。
然后我们还有两次切割,有三种选择的方式:
1:第二段为第二部分,末端加在第一部分。
2:首段为第一部分,第二段加在第一部分。
3:首段为第一部分,末端加在第一部分。
然后就是代码实现了:
import java.io.*;
import java.util.*;
public class Main {
public static void main(String args[]) throws IOException {
Scanner sc=new Scanner(System.in);
int arr[]=new int[10000]; //arr储存每个位置1的个数,以及开头和结尾的0
while(sc.hasNext()) {
int n=sc.nextInt();
int k=sc.nextInt();
int len=0;
String s=sc.next();
n=s.length();
for(int i=0;i<s.length();i++)
arr[i]=0;
//==============================求arr数组
boolean flag=false;
if(s.charAt(0)=='0')
len++;
for(int i=0;i<s.length();i++) {
if(s.charAt(i)=='1') {
flag=true;
arr[len]++;
}
else if(s.charAt(i)=='0'&&flag) {
flag=false;
len++;
}
}
//==============================
//如果数组长度为1,或者没有操作次数为0,则直接输出前缀1
if(len==0||k==0) {
System.out.println(arr[0]);
continue;
}
len++;
//从中间能取得的第一部分的个数
int t=Math.min((k-1)/2, len-2);
Arrays.sort(arr, 1,len-1);
int sum=0;
for(int i=1;i<=t;i++) {
sum+=arr[len-1-i];
}
if(len-t>2) { //然后考虑前端和末端
if(k%2==0) {
sum+=arr[0]+arr[len-1]+arr[len-2-t];
sum-=Math.min(arr[0], Math.min(arr[len-t-2], arr[len-1]));
}
else {
sum+=Math.max(arr[0]+arr[len-1], arr[len-t-2]);
}
}
else {
sum+=arr[0];
if(k>=1)
sum+=arr[len-1];
}
System.out.println(sum);
}
}
}