作业(Dp-贪心)

作业(homework)

题目背景:

众所周知,白神是具有神奇的能力的。

比如说,他对数学作业说一声“数”,数学作业就会出于畏惧而自己完成;对语文作业说一声“语”,语文作业就会出于畏惧而自己完成。

今天,语文老师和数学老师布置了许多作业,同学们纷纷寻找白神寻求帮助。白神作为一个助人为乐的人,便答应下来。

回到家,白神将这N份作业按顺序摊开,发现语文作业数学作业混在一起,这就让白神苦恼起来,他如果对连续一段作业喊出“数”,那么里面的语文作业就会由于过于慌乱而写满错解,不过如果白神再对其喊一声“语”,它又会写满正确答案。

虽然白神很强大,但是能力还是有限制的,一天只能使用K次,现在,白神想知道他能正确的完成多少份作业。

输入格式:

第一行两个整数N,K。

第二行N个0或者1表示这份作业是语文作业还是数学作业。

输出格式:

输出一个整数,表示白神能正确完成的作业数。

Input

5 2

0 10 1 0

Output

4

数据规模:

30%的数据中N ≤ 30,K<=10;

80%的数据中N ≤ 1000,K<=10;

100%的数据中N ≤ 100000,K<=50.



贪心:1个点最多刷2遍,第一次最好全刷(刷一段能行的全刷也行)

于是得出接下来肯定是一段一段刷(不相交)

然后Dp/

注意可能不只k-1部分

0..0 1..1 0..0 1..1 0..0  / 第一次刷0

这样的话可能有最后多出来的0部分

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<cmath>
#include<cctype>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define RepD(i,n) for(int i=n;i>=0;i--)
#define MAXN (100000+10)
#define MAXK (50+10)
int n,k,a[MAXN],ans=0;
int f[MAXN][MAXK][2]; //到n取k 0:未取 1:续取
void dp()
{
    memset(f,0,sizeof(f));
    For(i,n)
    {
        Rep(j,k+1)
        {
            f[i][j][0]=max(f[i-1][j][0],(!j)?0:f[i-1][j-1][1])+(a[i]==0);
            f[i][j][1]=max(f[i-1][j][1],f[i-1][j][0])+(a[i]==1);
        }
        f[i][k+1][0]=max(f[i-1][k+1][0],f[i-1][k][1])+(a[i]==0);
    }
//  ans=max(max(f[n][k][0],f[n][k][1]),ans);
    Rep(j,k+1) ans=max(max(f[n][j][0],f[n][j][1]),ans);
    ans=max(f[n][k+1][0],ans);
}
int main()
{
	freopen("homework.in","r",stdin);
	freopen("homework.out","w",stdout);
    scanf("%d%d",&n,&k);k-=2;
    For(i,n) scanf("%d",&a[i]);
    dp();
//  cout<<ans<<endl;
    For(i,n) a[i]^=1;
    dp();
    cout<<ans<<endl;


	return 0;
}




你可能感兴趣的:(作业(Dp-贪心))