A. Line Trip
思路:求出每个加油站之间间隔的最大值 和 第一个加油站到起点的值 和 最后一个加油站到终点的值的二倍(往返), 求出这三个值的最大值即可。
代码:
void solve(){
int n;cin>>n;
int x;cin>>x;
vector<int>a(n);
for(int i=0;i<n;i++)
cin>>a[i];
int mi=-1;
for(int i=1;i<n;i++){
mi=max(mi,a[i]-a[i-1]);
}
mi=max(mi,a[0]);
mi=max(mi,2*(x-a[n-1]));
cout<<mi<<endl;
}
B. Chip and Ribbon
思路:我们从前往后考虑
如果a[i]<=a[i-1]的话,每次到达i-1后,顺路到达i即可。对答案没有影响。
如果a[i]>=a[i-1]的话,到达i-1后,到达次数不能满足a[i],所以还要自行转移a[i]-a[i-1]次
代码:
void solve(){
int n;cin>>n;
vector<int>a(n+1);
for(int i=1;i<=n;i++)
cin>>a[i];
int ans=0;
for(int i=1;i<=n;i++)
ans+=max(a[i]-a[i-1],0ll);
cout<<ans-1<<endl;
}
C. Add, Divide and Floor
思路:让最大值和最小值相同,其他数字就自然相同了. 考虑怎么操作,首先可以发现加奇数等价于加一,加偶数等价于加零,所以只考虑加一或者加零即可. 可以发现如果最小值当前是奇数,就加一,否则就加零,感性理解一下这样操作可以让最小值减少的较少,有利于让最小值接近最大值.
代码:
void solve() {
int n;
cin >> n;
int mn = 1e9, mx = 0;
for (int i = 0; i < n; ++i) {
int a;
cin >> a;
mn = min(mn, a);
mx = max(mx, a);
}
vector<int> ans;
while (mn != mx) {
if (mn % 2 == mx % 2) {
ans.push_back(0);
} else if (mx % 2 == 0) {
ans.push_back(1);
++mn;
++mx;
} else {
ans.push_back(0);
}
mn /= 2;
mx /= 2;
}
cout << ans.size() << "\n";
if ((int)ans.size() <= n) {
for (int x : ans) {
cout << x << " ";
}
cout << "\n";
}
}
D. Yet Another Monster Fight
思路:
i左侧的怪物j最坏受到x-(i-j)-(n-i)点伤害,得到x+j-n>=a[j] --> x>=a[j]-j+n
i右侧的怪物j最坏受到x-(j-i)-(i-1)点伤害,得到x-j+1>=a[j] --> x>=a[j]+j-1
预处理一下前缀和后缀最值即可
代码:
void solve() {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
vector<int> pref(n + 1), suf(n + 1);
pref[0] = -1;
for (int i = 0; i < n; ++i) {
pref[i + 1] = max(pref[i], a[i] + n - i - 1);
}
suf[n] = -1;
for (int i = n - 1; i >= 0; --i) {
suf[i] = max(suf[i + 1], a[i] + i);
}
int ans = 2e9;
for (int i = 0; i < n; ++i) {
ans = min(ans, max(pref[i], max(a[i], suf[i + 1])));
}
cout << ans << "\n";
}