老师良心推荐的二分题。7月29号第一次写,想到了裸的DP,乱搞搞过了6组,欲优化,无解,弃疗。
然后今天老师给了题解,简单看了一下。
正解是二分答案+DP验证。
二分天数$day$,然后对于每次二分出的$day$,设$f[i][j]$表示对于前$i$个人,完成$j$份A工作时可以完成的最多的$B$工作。
这个的状态转移方程很好写出:
$f[i][j]=max \left\{f[i-1][j-d/a[i].first]+(day-d)/a[i].second \right\}$
$ 0\leq d \leq day$
具体实现:
1 //OJ 1817 2 //by Cydiater 3 //2016.9.22 4 #include <iostream> 5 #include <cstdio> 6 #include <cstring> 7 #include <string> 8 #include <algorithm> 9 #include <queue> 10 #include <map> 11 #include <ctime> 12 #include <cmath> 13 #include <cstdlib> 14 #include <iomanip> 15 using namespace std; 16 #define ll long long 17 #define up(i,j,n) for(int i=j;i<=n;i++) 18 #define down(i,j,n) for(int i=j;i>=n;i--) 19 #define pii pair<int,int> 20 const int MAXN=105; 21 const int oo=0x3f3f3f3f; 22 inline int read(){ 23 char ch=getchar();int x=0,f=1; 24 while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();} 25 while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} 26 return x*f; 27 } 28 pii a[MAXN]; 29 int N,M,leftt,rightt,mid,f[MAXN][MAXN]; 30 namespace solution{ 31 inline pii get(){ 32 int x,y; 33 x=read();y=read(); 34 return make_pair(x,y); 35 } 36 void init(){ 37 N=read();M=read(); 38 up(i,1,N)a[i]=get(); 39 } 40 bool check(int day){ 41 memset(f,-10,sizeof(f)); 42 f[0][0]=0; 43 up(i,1,N)up(j,0,M)up(d,0,day)if(j*a[i].first>=d) 44 f[i][j]=max(f[i][j],f[i-1][j-d/a[i].first]+(day-d)/a[i].second); 45 return f[N][M]>=M; 46 } 47 int slove(){ 48 leftt=1;rightt=100; 49 while(leftt+1<rightt){ 50 mid=(leftt+rightt)>>1; 51 if(check(mid)) rightt=mid; 52 else leftt=mid; 53 } 54 if(check(leftt)) return leftt; 55 return rightt; 56 } 57 } 58 int main(){ 59 //freopen("input.in","r",stdin); 60 using namespace solution; 61 init(); 62 printf("%d\n",slove()); 63 return 0; 64 }
时间: 2024-11-03 22:39:02