题解 P2214 【[USACO14MAR]Mooo Moo S】

· · 题解

Part 0 前言

USACO的典型背包题。

确实非常典型,建议背包萌新一刷。

Part 1 题意

FJ 把 b 种奶牛放养在 n 块农田里。每一种奶牛有一个数值 v_i,表示奶牛发出的声音大小。受到风的影响,一片农田的声音为前一片农田的声音加上在这片农田上的奶牛的声音响度之和减一。给出v_{1\widetilde{\;\;}b} 和每片农田上的声音,如果有方案的话,输出最少的奶牛数,否则输出 -1

Part 2 做法

是一道裸的完全背包题,但是需要先进行一些处理:

则转移方程为 $f_i=\min(f_i,\;f_{i-v_i}+1)$(注意是 $\min$ 不是 $\max$), 初始状态为 $f_{1\widetilde{\;\;}MAX}=INF\;\;(MAX=10^5)$ ($f_0=0$)。 不过这样还是不够,需要对开始的农田声音响度进行预处理。 即设置一个变量 `l(last)` 表示上一片农田遗留下的声音大小。 然后对读入的数减去 $\max(l,0)$(`l`有可能为$0$),并每次对`l`进行更新。 这样就能够愉快地 $\color{white}\colorbox{green}{AC}$掉本题啦! ## Part 3 代码 这个代码中的`m`就是题目描述中的`b`。 ```c++ #include<bits/stdc++.h> #define int long long using namespace std; int const N=233,MAX=233333,INF=0x3f3f3f3f; int n,m,l,ans,a[N],v[N],f[MAX]; signed main(){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); cin>>n>>m; for(int i=1;i<=MAX;i++)f[i]=INF; for(int i=1;i<=m;i++)cin>>v[i]; for(int i=1;i<=m;i++) for(int j=v[i];j<=MAX;j++) f[j]=min(f[j],f[j-v[i]]+1); for(int i=1,x;i<=n;i++) cin>>x,ans+=f[x-max(l,0ll)],l=x-1; cout<<(ans>=INF?-1:ans); } ```