Problem
T1
略。
T2
略。
T3
结论题。
令所有牛的最终饥饿值为 \(x\),则分别对于每一头牛进行考虑:
-
对于第一头牛,它需要的最少玉米袋数为 \(h_1-x\);
-
对于第二头牛,它单独需要的最少玉米袋数为 \(h_2-x\),而第一头牛已经用了 \(h_1-x\) 袋玉米,因此它需要的最少玉米袋数为 \(h_2-x-(h_1-x)=h_2-h_1\)。
-
对于第三头牛,它单独需要的最少玉米袋数为 \(h_3-x\),而第二头牛已经用了 \(h_2-h_1\) 袋玉米,因此它需要的最少玉米袋数为 \(h_3-x-(h_2-h_1)=h_3-h_2+h_1-x\)。
-
\(......\)
从上述推导可知,每一头牛需要的最少玉米袋数去掉 \(-x\) 之后每一项都是 \(h_i\) 减去前一项得到,同时每个偶数项均为 \(0\)。
而我们又发现,每一项去除 \(-x\) 之后,就变成了最终的饥饿值。
因为每个偶数项均为 \(0\),则真正对于答案有贡献的只有奇数项。
所以 \(s-\min\{m_1\}\) 即为答案,
其中 \(s\) 为初始饥饿值之和,\(m_1\) 为奇数项去除 \(-x\) 之后的值。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,n,v,s;
int h[100031],m[2];
void solve(){
cin>>n,s=0;
for(int i=1;i<=n;i++) cin>>h[i],s+=h[i];
if(n==1) cout<<0<<'\n';
else{
v=h[1],m[1]=h[1],m[0]=h[2];
for(int i=2;i<=n;i++)
v=h[i]-v,m[i%2]=min(m[i%2],v);
if(min(m[0],m[1])<0||n%2==0&&v) cout<<-1<<'\n';
else cout<<s-m[1]*n<<'\n';
}
}
signed main(){
cin>>t;
while(t--) solve();
return 0;
}
T4
显然是 dp。
一种很朴素的做法就是先枚举起点,再对于两个方向进行 dp。但这样做复杂度过高,无法接受。
考虑反向思考:我们往左 / 右方向 dp,其实就相当于从终点往右 / 左方向 dp,这样我们就不用枚举起点,只用考虑方向即可。
具体地,我们对于每个满足 \(1 \le i \le n\) 的 \(i\),枚举它前面的满足 \(1 \le j < i\) 的 \(j\),和满足 \(i < k \le n\) 且 \(dis_{i,k} \ge dis_{j,i}\) 的 \(k\)(\(dis_{i,j}\) 表示 \(i,j\) 之间的距离),先取到最大的前置状态 \(dp_{k,i}\),然后 \(i\) 可以选择接上之前路径,也可以单独开辟路径,在两种选择中去最优即可。反之亦然。
#include<bits/stdc++.h>
using namespace std;
int n,ans=-1e9;
pair<int,int> a[1031];
int dp[1031][1031];
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i].first>>a[i].second,ans=max(ans,a[i].second);
sort(a+1,a+n+1);
for(int i=1;i<=n;i++){
for(int j=n,k=1,mx=0;j>i;j--){
for(;k<i&&a[j].first-a[i].first<=a[i].first-a[k].first;k++) mx=max(mx,dp[k][i]);
dp[i][j]=max(a[i].second+a[j].second,mx+a[j].second);
ans=max(ans,dp[i][j]);
}
}
for(int i=n;i>=1;i--){
for(int j=1,k=n,mx=0;j<i;j++){
for(;k>i&&a[i].first-a[j].first<=a[k].first-a[i].first;k--) mx=max(mx,dp[i][k]);
dp[j][i]=max(a[i].second+a[j].second,mx+a[j].second);
ans=max(ans,dp[j][i]);
}
}
cout<<ans;
return 0;
}