【資訊學奧賽一本通——高手訓練】軟體開發 | 二分、dp
阿新 • • 發佈:2021-01-18
技術標籤:資訊學奧賽一本通系列
題目大意:
現在有兩個軟體,每個軟體有 m m m個模組,有 n n n個員工,第i個員工完成 a a a軟體的一個模組需要 a i a_i ai天,完成 b b b軟體的一個模組需要 b i b_i bi天,問最少多少天可以完成兩個軟體?
題目思路:
最少
問題,分析一下,如果第
x
x
x天可以完成,那麼第
x
+
1
x+1
x+1天肯定也可以完成,所以這是一個具有單調性的題目。
所以我們可以二分這個
x
x
x,判斷
x
x
x天可以完成,那麼問題就轉換為了判斷
x
x
x天是否可以完成這兩個軟體的開發。因為現在固定了天數
x
x
x,所以對於每一個人我們可以給其分配有多少天處理
a
a
a模組,有多少天處理
b
b
b模組。所以我們可以用
d
p
dp
dp求解,將每個人看成一個組,每個組可以有多種選擇(多少天處理
a
a
a軟體),這樣就是一個分組揹包問題了:
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]就代表前i個物品,處理了
a
a
a軟體的
j
j
j個模組最多能處理
b
b
b軟體多少個模組。
這種型別的 d p dp dp在cf上也有一個,不過沒寫題解。
Code:
/*** keep hungry and calm CoolGuang! ***/
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e17+7;
const ll maxn = 1e7+700;
const ll mod= 998244353;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
ll dp[105][105];///前i個,完成了軟體1的k個模型,軟體2最多完成幾個模型
int a[maxn],b[maxn];
int judge(int x){
memset(dp,-1,sizeof(dp));
dp[0][0] = 0;
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++) dp[i][j] = dp[i-1][j];
for(int k=0;k*a[i]<=x;k++){
int op = (x - k*a[i])/b[i];///此時還能給軟體b做的貢獻
for(int j=k;j<=m;j++){
if(~dp[i-1][j-k]) dp[i][j] = max(dp[i-1][j-k]+op,dp[i][j]);
}
}
}
return dp[n][m] >= m;
}
int main(){
read(n);read(m);
for(int i=1;i<=n;i++){
read(a[i]);
read(b[i]);
}
int l = 1,r = 20000;
int ans = 0;
while(l<=r){
int mid = (l+r)/2;
if(judge(mid)){
r = mid-1;
ans = mid;
}else l = mid+1;
}
printf("%d\n",ans);
return 0;
}
/***
2 20 16
Alexstrasza
Alexstrasza
***/