P3092 [USACO13NOV] No Change G

/*
k<=16->状态dp
有n个物品 k枚硬币 可以随时停下来 按顺序购买 之前累计的未付款 货物 但不能找零 问最多可以剩下多少钱 / -1 1.f[i][j]:i物品从j开始 可以连续买几个->到编号几 2.dp[i]:在硬币选择上 i 状态 最多到第几个 :i 0~(1<<k)-1 :j 1~k dp[i|(1<<j-1)]=max(dp[i|(1<<j-1)],f[j][dp[i]+1]) 3.直接枚举没有选择的硬币面值 */ /* 3 6 12 15 10 6 3 3 2 3 7 12 */ #include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<string.h> #include<queue> #include<vector> #include<bits/stdc++.h> #define ll long long #define ddd printf("-----------------------\n"); using namespace std; const int maxn=1e5 +10; const int mod=998244353; const int inf=0x3f3f3f3f; int n,k,coin[20],cost[100010]; int f[20][100010],dp[(1<<17)+10]; ll ans=-1; int main() { ios::sync_with_stdio(false); cin>>k>>n; for(int i=1;i<=k;i++) cin>>coin[i];//cout<<coin[i]<<endl; for(int i=1;i<=n;i++) cin>>cost[i]; for(int i=1;i<=k;i++){ int all=0,r=1; for(int j=1;j<=n;j++){ //int all=0,r=j; while(all+cost[r]<=coin[i]&&r<=n) all+=cost[r++]; f[i][j]=r-1; if(all) all-=cost[j]; } } //for(int i=1;i<=n;i++) cout<<f[1][i]<<" "; cout<<endl; for(int i=0;i<(1<<k);i++) { for(int j=1;j<=k;j++) { if(i&(1<<(j-1))) continue; if(dp[i]>=n) continue; dp[i|(1<<(j-1))]=max(dp[i|(1<<(j-1))],f[j][dp[i]+1]); } } for(int i=0;i<(1<<k);i++){ if(dp[i]<n) continue; ll tmp=0; for(int j=1;j<=k;j++){ if((~i)&(1<<(j-1))) tmp+=coin[j]; } ans=max(ans,tmp); } cout<<ans<<'\n'; return 0; }

 

posted @ 2023-11-21 03:34  JMXZ  阅读(22)  评论(0)    收藏  举报