软件开发 [CJOJ 1101] [NOIP 模拟]

时间:2021-11-09 18:13:38

Description

一个软件开发公司同时要开发两个软件,并且要同时交付给用户,现在公司为了尽快完成这一任务,将每个软件划分成m个模块,由公司里的技术人员分工完成,每个技术人员完成同一软件的不同模块的所用的天数是相同的,并且是已知的,但完成不同软件的一个模块的时间是不同的,每个技术人员在同一时刻只能做一个模块,一个模块只能由一个人独立完成而不能由多人协同完成。一个技术人员在整个开发期内完成一个模块以后可以接着做任一软件的任一模块。写一个程序,求出公司最早能在什么时候交付软件。

Input

输入文件第一行包含两个由空格隔开的整数n和m,其中1≤n≤100,1≤m≤100。接下来的n行每行包括两个用空格隔开的整数d1和d2,d1表示该技术人员完成第一个软件中的一个模块所需的天数,d2表示该技术人员完成第二个软件中的一个模块所需的天数,其中1≤d1,d2≤100。

Output

输出文件仅有一行包含一个整数d,表示公司最早能于d天后交付软件。

Sample Input

3 20
1 1
2 4
1 6

Sample Output

18

Hint

样例解释:
样例的最快方案是第一个技术人员完成第二个软件的18个模块,用时18天,第三个技术人员完成第一个软件的18个模块,用时18天,其余的模块由第二个技术人员完成,用时12天,做完所有模块需要18天。如果第一个技术人员完成第二个软件的17个模块,第三个技术人员完成第一个软件的17个模块,其余的模块由第二个技术人员完成,需要用时18天,做完所有模块仍然需要18天,所以少于18天不可能做完所有模块。

数据范围:
20%的数据1≤n,m≤10
40%的数据1≤n,m≤20
100%的数据1≤n,m,d1,d2≤100

思路

求所有人完成时间最长的最小值-->最大/小 化 最/大小值-->二分答案

如何验证在时间lim的范围之内是否能完成工作?

我们发现由于同一个人分配在1、2上面的时间不同,会对结果产生影响,所以我们要解决两个工作之间的干扰问题

由于n,m不大,试着枚举前i个人在总共做了j项工作1时,剩下还可以做工作2份数的最大值,设为dp[i][j]

枚举第i个人做了k份工作i,则状态转移方程为:

  dp[i][j]=max{ dp[i][j-k] + (lim-a[i]*k) / b[i] }

最后如果dp[n][m]<m,则不能完成,反之则可以;

重点: 当有两条主线时可以考虑处理一条,检验另一条

代码

 #include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define RG register int
#define rep(i,a,b) for(RG i=a;i<=b;i++)
#define per(i,a,b) for(RG i=a;i>=b;i--)
#define inf (1<<30)
#define maxn 105
using namespace std;
int n,m;
int a[maxn],b[maxn],dp[maxn][maxn];
inline int read()
{
int x=,f=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
} bool check(int lim)
{
memset(dp,-,sizeof(dp));dp[][]=;
rep(i,,n)
rep(j,,m)
for(RG k=,lm=min(j,lim/a[i]);k<=lm;k++)
dp[i][j]=max(dp[i-][j-k]+(lim-a[i]*k)/b[i],dp[i][j]);
if(dp[n][m]<m) return ;
return ;
} int main()
{
int mx=,l=,r,mid,ans=;
n=read(),m=read();
rep(i,,n) a[i]=read(),b[i]=read(),mx=max(mx,max(b[i],a[i]));
r=mx*m;
while(l<=r)
{
mid=(l+r)>>;
if(check(mid)) ans=mid,r=mid-;
else l=mid+;
}
cout<<ans;
return ;
}