题意: ......
分析: 二分答案,对于当前二分到的答案,验证在这个时间内是否可以完成,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;
}