BZOJ 3791: 作业

本文通过一个有趣的故事背景介绍了一个关于作业优化的问题。利用动态规划的方法,文章详细解释了如何通过覆盖区间来最大化正确完成作业的数量,并给出了具体的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:众所周知,白神是具有神奇的能力的。比如说,他对数学作业说一声“数”,数学作业就会出于畏惧而自己完成;对语文作业说一声“语”,语文作业就会出于畏惧而自己完成。今天,语文老师和数学老师布置了许多作业,同学们纷纷寻找白神寻求帮助。白神作为一个助人为乐的人,便答应下来。回到家,白神将这N份作业按顺序摊开,发现语文作业数学作业混在一起,这就让白神苦恼起来,他如果对连续一段作业喊出“数”,那么里面的语文作业就会由于过于慌乱而写满错解,不过如果白神再对其喊一声“语”,它又会写满正确答案。虽然白神很强大,但是能力还是有限制的,一天只能使用K次,现在,白神想知道他能正确的完成多少份作业。

如果真能这样该多好…其实最优的做法肯定是每一次覆盖都是选取前面覆盖范围内的一段,这样可以把序列分成2*K-1个不同的段,这样就可以DP辣.f[i][j][k]表示到第i个数分成j段,最后一段的值为k,转移并不困难: f[i][j][k]=max(f[i-1][j-1][k^1],f[i-1][j][k])+(a[i]==k)
Tips: 滚动数组

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=100000+10;
int f[3][101][2],n,k,a[maxn],ans;
int main()
{
  //freopen("3791.in","r",stdin);
  //freopen("3791.out","w",stdout);
  scanf("%d%d",&n,&k);
  for(int i=1;i<=n;i++) scanf("%d",&a[i]);
  f[1][1][a[1]]=1;
  f[1][1][a[1]^1]=0;
  k=2*k-1;
  for(int i=2;i<=n;i++)
  {
    for(int j=1;j<=k;j++)
      for(int l=0;l<2;l++)
      {
        f[i%2][j][l]=f[(i-1)%2][j][l]+(a[i]==l);
        if(j>1) f[i%2][j][l]=max(f[i%2][j][l],f[(i-1)%2][j-1][l^1]+(a[i]==l));
        ans=max(ans,f[i%2][j][l]);
      }
    for(int j=1;j<=k;j++)
     for(int l=0;l<2;l++)
       f[(i+1)%2][j][l]=0;
  }
  printf("%d\n",ans);
  return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值