2018百度之星(A)度度熊剪纸条

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;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/curry___/article/details/81630650