AC代码与思路
相比于最后一次TLE背包提交,加了以下这些
1 for (int j=1 ;j<=x-sumYen;j++) {
1 2 if (sumYen>x) return false ;
主要思路是二分答案加背包dp
背包容量为钱,背包价值为能加工多少产品
通过背包dp让加工产品最大化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include <iostream> #include <cmath> typedef long long ll;using namespace std;const ll MAXN=105 ,MAXANS=static_cast <ll>(1e9 )+7 ,MAXA=1e7 +7 ;int n,x,mach[MAXN][6 ];int dp[MAXA];inline bool check (ll needCap) { ll sumYen=0 ; for (int i=1 ;i<=n;i++) { dp[0 ]=0 ; int cap1=mach[i][1 ],p1=mach[i][2 ],cap2=mach[i][3 ],p2=mach[i][4 ]; bool isBreak=false ; if (sumYen>x) return false ; for (int j=1 ;j<=x-sumYen;j++) { int up1=j-p1,up2=j-p2; if (up1>=0 ) dp[j]=dp[up1]+cap1; if (up2>=0 ) dp[j]=max (dp[j],dp[up2]+cap2); if (dp[j]>=needCap) { sumYen+=j;isBreak=true ;break ; } } if (!isBreak) return false ; } if (sumYen<=x) return true ; return false ; } int main () { ios::sync_with_stdio (false ); cin.tie (0 );cout.tie (0 ); cin>>n>>x; for (int i=1 ;i<=n;i++) { cin>>mach[i][1 ]>>mach[i][2 ]>>mach[i][3 ]>>mach[i][4 ]; } ll l=0 ,r=MAXANS; while (l<r) { ll mid=l+r+1 >>1 ; if (check (mid)) l=mid; else r=mid-1 ; } cout<<l<<endl; return 0 ; }
以下是错误提交记录与心路历程
这个程序实际上没啥太大问题,但是即便开long long minYen还是超范围溢出了。
这个题目再次证明了,二分的题目r不能设太大,一个是复杂度,还有一个是溢出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <iostream> typedef long long ll;using namespace std;const ll MAXN=105 ,MAXANS=static_cast <ll>(1e13 )+7 ;ll n,x,mach[MAXN][6 ]; inline bool check (ll needCap) { ll sumYen=0 ; for (int i=1 ;i<=n;i++) { if (sumYen>x) return false ; ll cap1=mach[i][1 ],p1=mach[i][2 ],cap2=mach[i][3 ],p2=mach[i][4 ]; ll minYen=0 ;ll needMach1=(needCap-1 )/cap1+1 ,needMach2=(needCap-1 )/cap2+1 ; minYen=needMach1*p1; minYen=min (minYen,needMach2*p2); sumYen+=minYen; } if (sumYen<=x) return true ; return false ; } int main () { ios::sync_with_stdio (false ); cin.tie (0 );cout.tie (0 ); cin>>n>>x; for (int i=1 ;i<=n;i++) { cin>>mach[i][1 ]>>mach[i][2 ]>>mach[i][3 ]>>mach[i][4 ]; } ll l=0 ,r=MAXANS; while (l<r) { ll mid=l+r+1 >>1 ; if (check (mid)) l=mid; else r=mid-1 ; } cout<<l<<endl; return 0 ; }
原来两台机子都能用!那check()函数写起来是比较麻烦
1 2 Both machines S_i and T_i can be used for process i. If you purchase both machines S_i and T_i, the number of items that can be processed in process i will be the sum of the items processed by both machines.
AC 64 个点 https://atcoder.jp/contests/abc374/submissions/58537475
加上了对于组合的判定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include <iostream> typedef long long ll;using namespace std;const ll MAXN=105 ,MAXANS=static_cast <ll>(1e10 )+7 ;ll n,x,mach[MAXN][6 ]; inline bool check (ll needCap) { ll sumYen=0 ; for (int i=1 ;i<=n;i++) { if (sumYen>x) return false ; ll cap1=mach[i][1 ],p1=mach[i][2 ],cap2=mach[i][3 ],p2=mach[i][4 ]; ll minYen;ll needMach1=(needCap-1 )/cap1+1 ,needMach2=(needCap-1 )/cap2+1 ; minYen=min (needMach1*p1,needMach2*p2); ll firstMach1=needCap/cap1,remainMach2=(needCap-firstMach1*cap1-1 )/cap2+1 ; ll priceComb1=firstMach1*p1+remainMach2*p2; ll firstMach2=needCap/cap2,remainMach1=(needCap-firstMach2*cap2-1 )/cap1+1 ; ll priceComb2=firstMach2*p2+remainMach1*p1;; minYen=min (minYen,min (priceComb1,priceComb2)); sumYen+=minYen; } if (sumYen<=x) return true ; return false ; } int main () { ios::sync_with_stdio (false ); cin.tie (0 );cout.tie (0 ); cin>>n>>x; for (int i=1 ;i<=n;i++) { cin>>mach[i][1 ]>>mach[i][2 ]>>mach[i][3 ]>>mach[i][4 ]; } ll l=0 ,r=MAXANS; while (l<r) { ll mid=l+r+1 >>1 ; if (check (mid)) l=mid; else r=mid-1 ; } cout<<l<<endl; return 0 ; }
我怀疑是我的向上取整模版的问题
1 2 3 4 5 6 7 8 9 10 11 #include <iostream> #include <cmath> using namespace std;long long a=0 ;int main () { cout<<-1 /782 <<endl; std::cout << (0 -1 )/782 +1 << std::endl; cout<<ceil (a/1.0 /782 )<<endl; return 0 ; }
毫无疑问,0/782=0,你就算加ceil()也应该是0,但显然我们的模版出了问题。
哎,用系统ceil()提交了一遍,发现又WA了,和前面一模一样,只能说就这样吧,累了。
https://atcoder.jp/contests/abc374/submissions/58539387
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <iostream> #include <cmath> typedef long long ll;using namespace std;const ll MAXN=105 ,MAXANS=static_cast <ll>(1e10 )+7 ;ll n,x,mach[MAXN][6 ]; inline bool check (ll needCap) { ll sumYen=0 ; for (int i=1 ;i<=n;i++) { if (sumYen>x) return false ; ll cap1=mach[i][1 ],p1=mach[i][2 ],cap2=mach[i][3 ],p2=mach[i][4 ]; ll minYen;ll needMach1=ceil (needCap/1.0 /cap1),needMach2=ceil (needCap/1.0 /cap2); minYen=min (needMach1*p1,needMach2*p2); ll firstMach1=needCap/cap1,remainMach2=ceil ((needCap-firstMach1*cap1)/1.0 /cap2); ll priceComb1=firstMach1*p1+remainMach2*p2; ll firstMach2=needCap/cap2,remainMach1=ceil ((needCap-firstMach2*cap2)/1.0 /cap1); ll priceComb2=firstMach2*p2+remainMach1*p1;; minYen=min (minYen,min (priceComb1,priceComb2)); sumYen+=minYen; } if (sumYen<=x) return true ; return false ; } int main () { ios::sync_with_stdio (false ); cin.tie (0 );cout.tie (0 ); cin>>n>>x; for (int i=1 ;i<=n;i++) { cin>>mach[i][1 ]>>mach[i][2 ]>>mach[i][3 ]>>mach[i][4 ]; } ll l=0 ,r=MAXANS; while (l<r) { ll mid=l+r+1 >>1 ; if (check (mid)) l=mid; else r=mid-1 ; } cout<<l<<endl; return 0 ; }
引入了性价比概念,但发现连样例都过不了😂,还是要用dp。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include <iostream> #include <cmath> typedef long long ll;using namespace std;const ll MAXN=105 ,MAXANS=static_cast <ll>(1e9 )+7 ,MAXA=1e7 +7 ;ll n,x,mach[MAXN][6 ]; int dp[MAXA];inline bool check (ll needCap) { ll sumYen=0 ; for (int i=1 ;i<=n;i++) { if (sumYen>x) return false ; ll sumCap=0 ,capA=mach[i][1 ],pA=mach[i][2 ],capB=mach[i][3 ],pB=mach[i][4 ]; while (true ) { if (sumCap>=needCap) break ; ll remainCap=needCap-sumCap; double effA=pA*1.0 /min (remainCap,capA); double effB=pB*1.0 /min (remainCap,capB); if (effA<effB) sumCap+=capA,sumYen+=pA; else sumCap+=capB,sumYen+=pB; } } if (sumYen<=x) return true ; return false ; } int main () { ios::sync_with_stdio (false ); cin.tie (0 );cout.tie (0 ); cin>>n>>x; for (int i=1 ;i<=n;i++) { cin>>mach[i][1 ]>>mach[i][2 ]>>mach[i][3 ]>>mach[i][4 ]; } ll l=0 ,r=MAXANS; while (l<r) { ll mid=l+r+1 >>1 ; if (check (mid)) l=mid; else r=mid-1 ; } cout<<l<<endl; return 0 ; }
将中间的判定改为了背包dp,果然这种通用做法就是应用性广泛且经过证明
// 就TLE了3个点 https://atcoder.jp/contests/abc374/submissions/58545771
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 #include <iostream> #include <cmath> typedef long long ll;using namespace std;const ll MAXN=105 ,MAXANS=static_cast <ll>(1e9 )+7 ,MAXA=1e7 +7 ;int n,x,mach[MAXN][6 ];int dp[MAXA];inline bool check (ll needCap) { ll sumYen=0 ; for (int i=1 ;i<=n;i++) { dp[0 ]=0 ; int cap1=mach[i][1 ],p1=mach[i][2 ],cap2=mach[i][3 ],p2=mach[i][4 ]; bool isBreak=false ; if (sumYen>x) return false ; for (int j=1 ;j<=x-sumYen;j++) { dp[j]=0 ; int up1=j-p1,up2=j-p2; if (up1>=0 ) dp[j]=dp[up1]+cap1; if (up2>=0 ) dp[j]=max (dp[j],dp[up2]+cap2); if (dp[j]>=needCap) { sumYen+=j;isBreak=true ;break ; } } if (!isBreak) return false ; } if (sumYen<=x) return true ; return false ; } int main () { ios::sync_with_stdio (false ); cin.tie (0 );cout.tie (0 ); cin>>n>>x; for (int i=1 ;i<=n;i++) { cin>>mach[i][1 ]>>mach[i][2 ]>>mach[i][3 ]>>mach[i][4 ]; } ll l=0 ,r=MAXANS; while (l<r) { ll mid=l+r+1 >>1 ; if (check (mid)) l=mid; else r=mid-1 ; } cout<<l<<endl; return 0 ; }