洛谷 P1800 software(DP+二分)【提高+/省选−】
题目链接
https://www.luogu.com.cn/problem/P1800
思路
对于大于等于最优解的天数,一定能使公司交付软件。对于小于最优解的天数,一定无法使公司交付软件。所以考虑二分答案 x x x。
定义 f [ i ] [ j ] f[i][j] f[i][j]表示前 i i i个人做了 j j j个软件 1 1 1的模块时,他们最多还能多做多少个软件 2 2 2的模块。
因为每一个人都是相对独立的,所以转移方程为:
f [ i ] [ j ] = m a x ( f [ i − 1 ] [ k ] + ⌊ x − d 1 [ i ] × ( j − k ) d 2 [ i ] ⌋ ) f[i][j] = max(f[i-1][k] + \left \lfloor \frac{x - d1[i] \times (j - k)}{d2[i]} \right \rfloor ) f[i][j]=max(f[i−1][k]+⌊d2[i]x−d1[i]×(j−k)⌋)。
时间复杂度: O ( n m 2 l o g 2 2 e 4 ) O(nm^2log_{2}{2e4}) O(nm2log22e4)。
代码
#include <bits/stdc++.h>using namespace std;#define int long longconst int N = 1e2 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;int n, m;
int a[N], b[N], f[N][N];
bool check(int x)
{memset(f, -inf, sizeof f);f[0][0] = 0;for (int i = 1; i <= n; i++){for (int j = 0; j <= m; j++){for (int k = 0; k <= j; k++){if (x >= a[i] * (j - k))f[i][j] = max(f[i][j], f[i - 1][k] + (x - a[i] * (j - k)) / b[i]);}}}return f[n][m] >= m;
}
void solve()
{cin >> n >> m;for (int i = 1; i <= n; i++){cin >> a[i] >> b[i];}int low = 1, high = 2e4;while (low < high){int mid = low + high >> 1;if (check(mid)){high = mid;}else low = mid + 1;}cout << high << endl;
}signed main()
{ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);int t = 1;// cin >> t;while (t--)solve();return 0;
}