题意: ......
分析: 二分答案,对于当前二分到的答案,验证在这个时间内是否可以完成,dp[i][j]表示到第i个人时,完成了j个A任务时最多能完成B任务的个数。然后枚举第i个人完成A任务的个数k来转移,dp[i][j]=max{dp[i-1][j-k]+第i个人完成k个A任务后还能完成B任务的个数}。
#include <iostream>
#include <stdio.h>
#include <memory.h>
using namespace std;
int dp[110],a[110],b[110],maxx,n,m;
int judge(int now)
{
int i,j,k,tem;
memset(dp,-1,sizeof(dp));
for(j=0;j<=m;j++)
{
if(j*a[1]>now) break;
tem=now-j*a[1]; // 第一个人完成j个任务1后还剩的时间
tem=tem/b[1]; // 第一个人还能完成任务2的个数
dp[j]=tem;
}
for(i=2;i<=n;i++)
{
for(j=m;j>=0;j--) // 因为dp[]只用一维,所以类似完全背包 这里应该倒过来循环
{
for(k=0;k<=j;k++)
{
if(k*a[i]>now) break;
tem=now-k*a[i]; // 第i个人完成k个任务1后还剩的时间
tem=tem/b[i]; // 还能完成任务2的个数
if(dp[j-k]!=-1&&dp[j-k]+tem>dp[j])
dp[j]=dp[j-k]+tem;
}
}
if(dp[m]>=m) return 1;
}
return 0;
}
void solve()
{
int l=0,r=maxx*2*m,ans=r,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(judge(mid))
{
ans=mid;
r=mid-1;
}
else l=mid+1;
}
printf("%d\n",ans);
}
int main()
{
int t,i;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
maxx=0;
for(i=1;i<=n;i++)
{
scanf("%d%d",a+i,b+i);
if(a[i]>maxx) maxx=a[i];
if(b[i]>maxx) maxx=b[i];
}
solve();
}
return 0;
}