fj正在市場上為他的農場採購日用品,他口袋裡有k(1<=k<=16)個硬幣,每乙個硬幣的面值均在1~1,000,000,000之間。fj有乙個包含n(1<=n<=100,000)種待購物品的序列清單,其中第i種物品需要的錢數為c(i),(1<=c(i)<=10,000),在購物的過程中,他隨時可以停下來用一枚硬幣付一次錢,每次付錢的物件為從上次付錢之後至當前所有物品價值和(當然,他所付的硬幣面值也必須足夠大),不巧的是,市場上的商戶們都沒有零錢了,因此如果fj給的硬幣面值大於所購物品價值,他也不會得到找零!
請計算fj完成n件物品的購物後,所能剩下的最大錢數。如果他無法買到所有物品,輸出-1。
第1行:兩個整數k,n;
第2~k+1行:每行為乙個硬幣面值;
第k+2~n+k+1行:這n行為fj所要購買的n件物品的價值。
一行,即結束購物後fj所剩餘的最大錢數,輸出-1表示他無法完成購物。
3 612
151063
3237
輸出解釋:
fj花費面值為10的硬幣購買前兩件物品,然後花費面值為15的硬幣購買剩餘的4樣物品,最後剩餘一枚面值為12的硬幣。
我們先想到既然k這麼小,可以壓狀態,對於每一枚硬幣都是取或者不取,然後就可以愉快的寫出如下一些東西:
設f[i]表示用i這個組合的硬幣對於上一次可以搞的最遠距離,g[i]表示用這個組合搞出來的最大剩餘.
然後就發現:f[i]可以用二分查詢優化更新,g[i]隨著更新就好了.
#include#include#include#include#include#include#includeusing namespace std;
#define ll long long
#define re register
inline int gi()
while(ch>='0' && ch<='9')
return sum*f;
}int k,n,sum[1000010],ar[1000010],coin[1000010],f[1000010],g[1000010],ans=-1;
int find(int from,int x)
else r=mid-1;
}return wz;
}int main()sum[n+1]=2147483647;
for(re int i=1;i<(1<<16);i++)
}if(f[i]==n && g[i]>ans)ans=g[i];
}printf("%d\n",ans);
return 0;
}
CJOJ 免費航班
小z在moi比賽中獲得了大獎,獎品是一張特殊的機 票。使用這張機票,可以在任意乙個國家內的任意城市之間的免費飛行,只有跨國飛行時才會有額外的費用。小z獲得了一張地圖,地圖上有城市之間的飛機航班和 費用。已知從每個城市出發能到達所有城市,兩個城市之間可能有不止乙個航班。乙個國家內的每兩個城市之間一定有...
CJOJ 為了博多
做了個噩夢,夢見我的 n 把刀到60級會二次變身,變成乙個對推6圖有xi點貢獻,刷大阪城有yi點貢獻的刀,於是要把刀分成兩隊一隊刷大阪城另一隊推6圖 但是有m對兄弟刀在同一隊會有特殊的buff加成,加成值為wi,問怎樣分隊收益最大,最大值是多少。第一行兩個整數n 刀的數目 0 n 20000 m 兄...
CJOJ 1504 整數合併
現在給你一些連續的整數,它們是從 a 到 b 的整數。一開始每個整數都屬於各自的集合,然後你需要進行如下操作 每次選擇兩個屬於不同集合的整數,如果這兩個整數擁有大於等於 p 的公共質因子,那麼把他們所在的集合合併。反覆上述操作,直到沒有可以合併的集合為止。現在,小 x 想知道,最後有多少個集合。一行...