http://acm.hdu.edu.cn/showproblem.php?pid=6376
度度熊有一张纸条和一把剪刀。
纸条上依次写着 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背包,把连续为‘1’的字符串剪下,在开头和尾部的花费为1,其余在中间的花费为2,还有一个坑就是在中间的一个可剪下的放到最后就可以少减一次,例如101111001110011,需要剪6次可以把带‘1’的全部剪下,但如果把1111或111放到最后,就像这样1,11,1111,11100或1,11,111,111100只需5次就可完成,所以等到要用背包求的时候,需要把K++。
AC代码如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn=10010;
int f[maxn],k,n;
char c[maxn];
struct node
{
int cost,val;
}p[maxn];
int main()
{
while(cin>>n>>k){
memset(f,0,sizeof(f));
int tot=0;
int flag=false;
int sum=0;
cin>>c;
for(int i=0;i<n;i++){
if(c[i]=='0'&&flag==true){
flag=false;
if(tot==0&&c[0]=='1')
p[tot++]={1,sum};
else p[tot++]={2,sum};
sum=0;
}
if(c[i]=='1'){
flag=true;
sum++;
}
}
if(flag==true)
p[tot++]={1,sum};
if(k==0){
if(c[0]=='1')
cout<<p[0].val<<endl;
else cout<<0<<endl;
}
else{
k++;
for(int i=0;i<tot;i++)
for(int j=k;j>=0;j--){
if(j>=p[i].cost)
f[j]=max(f[j],f[j-p[i].cost]+p[i].val);
}
cout<<f[k]<<endl;
}
}
}