標籤:push 固定 怎麼辦 init cst 存在 print 來講 ace
補充一下我理解的中文題意。。
你要重新組裝電腦。。電腦有一些組件。。
你的預算有b,b(1~1e9),有n個組件。。
每個組件有類型和名稱以及價錢和品質
現在你要在不超過預算b的情況下。。
每個類型都買一個組件。。然後最終的品質由最小的品質決定
在此約束下問你在預算b之內能組裝的最大的品質是多少
對每個組件價錢範圍1e6,品質範圍1e9
===============
由於錢和品質沒有必然聯絡
所以我們不能直接從品質小的開始貪。。
也沒法從品質大的開始貪吧。。因為你還要保證你的錢要夠
按品質排序則錢是無序的。。這樣反正不好處理。。其他的處理方法我還沒有想到
所以說你要怎麼搞呢。。
a1,b1,a2,b2,a3,b3
c1,d1,c2,d2,c3,d3
x1,y1,x2,y2,x3,y3
因為一旦你的錢固定的話。。對於每一個枚舉的總錢數。。這裡的錢數是固定的。。
也就是dp中離散的錢數。。每一個枚舉的錢數狀態來說。。錢是固定的。。
所以你第一種取不取。。會對後面造成影響。。因為總錢數少了。。
好像也不是太好dp,如果算前i種物品剩餘錢數是j所能達到的最大的最小品質
我後來想算前i種物品能夠達到品質q的最小錢數。。但是由於q很大不能離散。。所以不能dp?這個理由好像很牽強。。
我現在也不是太清楚離散化和dp之間是什麼關係。。但是毫無疑問對於一些連續的問題dp解決不了
一種解法是說。。我們二分最後的品質q。。
之前我在糾結
如果大於等於q1的最便宜的所有零件的組合超過預算。。
大於等於q2(q2>q1)的最便宜的所有零件的組合卻不超過預算
但是這是不存在的。。q單調增加時。。最便宜的價格也單調遞增。。
價格雖然無序。。但隨著有序性質品質的單調遞增。。最小价格單調遞增。。
我大概是表達這個意思。。 因為如果品質小,這意味著你的選擇性更多(比品質大的),所以也就最小价格也就可能越小所以我們來二分一下最小品質。。因為每次都取最便宜的組件。。所以說。。其總價格也是單調遞增的,前面證過了。。所以對於每次二分的結果。。對每種組件取大於等於這個結果的最便宜的組件。。最後check超不超過預算超過就品質往左走。。不超過就往右走。。,最後就能求出大於等於q的最小預算 ,最後就能求出來大於等於q的最小預算在不超過總預算的情況下所能達到的最大的q
按理說我的下標只能到2..因為一共3個元素。。
但是。。下標3,4卻能訪問。。不報越界。。其值是一個野值吧。。
這一點我們以後一定要注意。。
但是你如果程式一開始你就訪問4.。就會停止運行。。
這個vector的trick一定要記好了。。
#include <iostream>#include <cstdio>#include <map>#include <vector>#include <cstring>#include <algorithm>using namespace std;int n,b,cnt;char op1[50];char op2[50];struct node{int x,q;node(int x,int q):x(x),q(q){}};typedef long long ll;const int maxn=1e3+7;vector<node> things[maxn];int mxcheap[maxn][maxn];bool cmp(node a,node b){return (a.q!=b.q)?a.q<b.q:a.x<b.x;}void init(){int i;for(i=0;i<maxn;++i) things[i].clear();}void Sort(){int i;for(i=0;i<cnt;++i) sort(things[i].begin(),things[i].end(),cmp);}bool check(int key){int i;ll sum=0; for(i=0;i<cnt;++i){ int left=0,right=things[i].size()-1,mid; while(left<=right){ mid=(left+right)>>1; if(things[i][mid].q<key) left=mid+1;else right=mid-1; } if(right+1<things[i].size()&&things[i][right+1].q>=key) right++; if(left>things[i].size()-1) { return false;} sum+=mxcheap[i][right]; } return (sum>b)?false:true;}int main(){ int t;scanf("%d",&t); while(t--){ scanf("%d%d",&n,&b);init(); int i,j,x,q,lq=-1,rq=-1;cnt=0; map<string,int> mp; for(i=0;i<n;++i){ scanf("%s%s%d%d",op1,op2,&x,&q); if(!mp.count(string(op1))){ mp[string(op1)]=cnt++; } things[mp[string(op1)]].push_back(node(x,q)); rq=(rq==-1)?q:max(q,rq); lq=(lq==-1)?q:min(q,lq); } Sort(); for(i=0;i<cnt;++i){ mxcheap[i][things[i].size()-1]=things[i].back().x; for(j=things[i].size()-2;j>=0;--j){ mxcheap[i][j]=min(things[i][j].x,mxcheap[i][j+1]); } } int left=lq,right=rq,mid,ans=-1; while(left<=right){ mid=(left+right)>>1; if(check(mid)){left=mid+1;} else{right=mid-1;} } if(check(right+1)) right++; printf("%d\n",right); } return 0;}
這裡我犯了一個錯。。那就是。。check中的二分寫錯了。。
即使寫對了也不對。。因為。。我以為品質最接近q的價格最便宜。。這隻是對所有等於q的東西來說。。
那麼對於大於q的可能更加便宜。。所以我們這裡需要預先處理出每種組件的i~size的區間的最小值。。
二分得到邊界即可。。但是對於二分來講。。我們應當既考慮left>size-1(size是vector的size)
也要考慮left<0,比如要求第一個》=q的元素的下標。。這裡如果全部大於key那麼right會小於0,
你要判斷right+1合不合法以免漏判,如果全部小於key那麼right=size-1,而left=size,此時left
就越界了。。這是妥妥的無解。。一定要注意這一點
性質:任何無序序列的區間i~n的最值都是單調的
hdu2333-貪心,如何去後效性,背包太大怎麼辦,如何最大化最小值,從無序序列中發掘有序性質