省選專練之[USACO13NOV]沒有找零No Change
阿新 • • 發佈:2018-11-02
約翰到商場購物,他的錢包裡有K(1 <= K <= 16)個硬幣,面值的範圍是1…100,000,000。
約翰想按順序買 N個物品(1 <= N <= 100,000),第i個物品需要花費c(i)塊錢,(1 <= c(i) <= 10,000)。
在依次進行的購買N個物品的過程中,約翰可以隨時停下來付款,每次付款只用一個硬幣,支付購買的內容是從上一次支付後開始到現在的這些所有物品(前提是該硬幣足以支付這些物品的費用)。不幸的是,商場的收銀機壞了,如果約翰支付的硬幣面值大於所需的費用,他不會得到任何找零。
請計算出在購買完N個物品後,約翰最多剩下多少錢。如果無法完成購買,輸出-1
記錄F(1<<i)時的最遠購物距離
然後列舉已經更新了什麼刷表法更新。
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; const int N=1e5+100; inline void read(int &x){ x=0; int f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-')f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } x*=f; } int S[N]={}; int C[21]={}; int F[(1<<17)]; int n,k; int Mx; int Get(int now,int Id){ int sum=S[Id]+C[now]; if(sum>S[n])return n; int pos=upper_bound(S+1,S+1+n,sum)-S-1; return max(pos,Id); } int main(){ memset(F,-1,sizeof(F)); F[0]=0; read(k); read(n); for(int i=1;i<=k;++i){ read(C[i]); } for(int i=1;i<=n;++i){ read(S[i]); S[i]+=S[i-1]; } int Mx=(1<<k)-1; for(int i=0;i<=Mx;++i){ if(F[i]==-1)continue; for(int j=0;j<k;++j){ if(!(i&(1<<j))){ F[i|(1<<j)]=max(F[i|(1<<j)],Get(j+1,F[i])); } } } int ans=-1; for(int i=0;i<=Mx;++i){ if(F[i]==n){ int now=0; for(int j=0;j<k;++j){ if(!(i&(1<<j))){ now+=C[j+1]; } } ans=max(ans,now); } } cout<<ans; }