剪草
又一道水题
【问题描述】
有 N 棵小草,编号 0 至 N-1。奶牛 Bessie 不喜欢小草,所以 Bessie 要用剪刀剪草,目标是使
得这 N 棵小草的高度总和不超过 H。在第 0 时刻,第 i 棵小草的高度是 h[i],接下来的每个整数时
刻,会依次发生如下三个步骤:
(1)每棵小草都长高了,第 i 棵小草长高的高度是 grow[i]。
(2)Bessie 选择其中一棵小草并把它剪平,这棵小草高度变为 0。注意:这棵小草并没有死掉,
它下一秒还会生长的。
(3)Bessie 计算一下这 N 棵小草的高度总和,如果不超过 H,则完成任务,一切结束,否则轮
到下一时刻。
你的任务是计算:最早是第几时刻,奶牛 Bessie 能完成它的任务?如果第 0 时刻就可以完成就
输出 0,如果永远不可能完成,输出-1,否则输出一个最早的完成时刻。
【输入】
第一行,一个整数 g,表示有 g 组测试数据,组数不超过四组。每组数据的格式是:
第一行,两个整数 N 和 H。 1 ≤ N ≤ 50,0 ≤ H ≤ 1000000。
第二行,N 个整数,表示 h[i]。0 ≤ h[i] ≤ 100000。
第三行,N 个整数,表示 grow[i]。1 ≤ grow[i] ≤ 100000。
一开始用了个小贪心
大循环是从小到大每局到第几天可以结束,因为可以证明这个次数不超过20,诶虽然不知道怎么怎么证
然后从枚举的这个第i天倒推回去,最后一天减去目前长的最高的,倒数第二天减去当天除去最后一天减掉过的最高的
因为我们剪掉的高度数永远不会变,所以可以这么做
#include<bits/stdc++.h>
using namespace std;
int T;
long long a[60],n,m,gr[60],suma,sumgr,b[60],c[60];
void init()
{
suma=sumgr=0;
for (int i=1; i<=n; i++)
{
scanf("%lld",&a[i]);
suma+=a[i];
}
for (int i=1; i<=n; i++)
{
scanf("%lld",&gr[i]);
sumgr+=gr[i];
}
}
int main()
{
freopen("grass.in","r",stdin);
freopen("grass.out","w",stdout);
scanf("%d",&T);
for (int oo=1; oo<=T; oo++)
{
bool ppp=true;
scanf("%lld%lld",&n,&m);
init();
if (suma+sumgr<=m) {printf("0\n"); ppp=false; continue;}
for (int i=1; i<=n; i++)
{
long long sumb=0;
for (int j=1; j<=n; j++)
{
b[j]=a[j]+gr[j]*i;
c[j]=b[j];
sumb+=b[j];
}
long long p=0;
for (int j=0; j<i; j++)
{
long long maxx=0,maxi=0;
for (int k=1; k<=n; k++)
{
b[k]=c[k]-j*gr[k];
if (b[k]>maxx) {maxx=b[k]; maxi=k;}
}
sumb-=b[maxi];
c[maxi]=0;
if (sumb<=m) {p=1; break;}
}
if (p==1) {printf("%d\n",i); ppp=false; break;}
}
if (ppp==true) printf("-1\n");
}
}
但是哎,毕竟是贪心,
1 50
10000 10000
1 49
这组数据,贪心旧先减去后面的,但这样会发现不对,贪心的答案是 3
但是其实先把前面的减掉,再减掉后面的就好了,所以答案是2
所以你应该想到了
DP
毕竟没法贪心的都用DP,这是铁律。
表示第 天 是否减的最优值。
取
或者
不取
哈
#include<bits/stdc++.h>
using namespace std;
int T,n,H,ans,dp[55][55],hsum,gsum;
struct node{
int h,grow;
bool operator < (const node b) const{
return grow<b.grow;
}
};
node grass[55];
int main(){
freopen("grass.in","r",stdin);
freopen("grass.out","w",stdout);
scanf("%d",&T);
while(T--){
ans=-1;
scanf("%d%d",&n,&H);
hsum=gsum=0;
for(int i=1;i<=n;i++) scanf("%d",&grass[i].h),hsum+=grass[i].h;
for(int i=1;i<=n;i++) scanf("%d",&grass[i].grow),gsum+=grass[i].grow;
sort(grass+1,grass+n+1);
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
dp[i][j]=max(dp[i-1][j],dp[i-1][j-1]+grass[i].h+grass[i].grow*j);
for(int t=0;t<=n;t++){
int sum=hsum+gsum*t;
if(sum-dp[n][t]<=H){
ans=t;
break;
}
}
printf("%d\n",ans);
}
}