膜拜 解题报告

洛谷P1564

题目描述

神牛有很多…当然…每个同学都有自己衷心膜拜的神牛.

某学校有两位神牛,神牛甲和神牛乙。新入学的N 位同学们早已耳闻他们的神话。

所以,已经衷心地膜拜其中一位了。现在,老师要给他们分机房。但是,要么保证整个机房都是同一位神牛的膜拜者,或者两个神牛的膜拜者人数差不超过M。另外,现在N位同学排成一排,老师只会把连续一段的同学分进一个机房。老师想知道,至少需要多少个机房。

输入输出格式

输入格式:

输入文件第一行包括N 和M。

之后N 行,每行一个整数,1 表示神牛甲的崇拜者,2 表示神牛乙的崇拜者。

输出格式:

输出一个整数,表示最小需要机房的数量。


这题啊。。。一看觉得是f(x)表示前n个人最少机房量。f(x)=min{f(x),f(x-1)+1};提交发现WA。为什么呢。。这样的话其实我们是在贪心。。一个机房一直装,直到装不下为止,没有达到整体最优。听人说将2改为-1,题目就变成了将序列最少分为多少段,使每段和的绝对值≤M。于是我们可以用前缀和算出前i个数之和。(石子合并中用到过)得到如下状态转移方程:

if(abs(sum[i]-sum[j-1])==i-j+1||abs(sum[i]-sum[j-1])<=m)dp[i]=min(dp[i],dp[j-1]+1);

从j段到i段如果可以装在一个机房中的话,dp[i]=min(dp[i],dp[j-1]+1);。

去枚举每一个j段 就可以AC了。核心代码如下:

计算前缀和与dp过程(切记!dp【0】=0;)

for(int i=1;i<=n;i++){
scanf("%d",&tem);
if(tem==1)sum[i]=sum[i-1]+1;
else sum[i]=sum[i-1]-1;
}

for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++){
if(abs(sum[i]-sum[j-1])==i-j+1||abs(sum[i]-sum[j-1])<=m)dp[i]=min(dp[i],dp[j-1]+1);

你可能感兴趣的:(DP)