A. Line Trip
签到
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> p3;
int mod = 1e9+7;
const int maxv = 4e6 + 5;
// #define endl "\n"
void solve()
{
int n,x;
cin>>n>>x;
vector<int> a(n+5);
for(int i=1;i<=n;i++) cin>>a[i];
int ans=0;
for(int i=1;i<=n;i++){
ans=max(ans,a[i]-a[i-1]);
}
ans=max(ans,(x-a[n])*2);
cout<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
t=1;
cin>>t;
while(t--){
solve();
}
system("pause");
return 0;
}
B. Chip and Ribbon
题意:
有一条带子被分成
n
n
n 个单元格,从左到右编号为
1
1
1 到
n
n
n 。最初,每个单元格中都写有一个整数
0
0
0 。
单果与芯片玩游戏。游戏由几个回合组成。在第一轮中,Monocarp 将芯片放入色带的 1 1 1 st 单元。除了第一轮之外,在每一轮中,魔卡都会做以下两个动作中的一个:
- 将芯片移动到下一个单元格(例如,如果芯片在 i i i 单元格,则将其移动到 i + 1 i+1 i+1 单元格)。如果芯片在上一格,则无法进行此操作;
- 选择任意一个 x x x 单元格,将芯片传送到该单元格。可以选择芯片当前所在的单元格。
每回合结束时,写入芯片所在单元格的整数会增加 1 1 1 。
Monocarp的目标是在某些回合中使 1 1 1-st 单元格中包含整数 c 1 c_1 c1 , 2 2 2 -nd单元格中包含整数 c 2 c_2 c2 ,…, n n n -\th单元格中包含整数 c n c _n cn 。他希望尽可能少地传送芯片。
请帮助 Monocarp 计算他传送芯片的最少次数。
思路:我们考虑,对于第一个单元格,其对答案的贡献一定是 a [ 1 ] − 1 a[1]-1 a[1]−1,再考虑其他情况,若整个序列为递减序列,那么其他的单元格对答案的贡献均为0,因为我们每次都是从第一个单元格开始,还能控制终止位置。因此不会出现其他单元格为起点的情况。推广到特殊情况,对于元素 i − 1 i-1 i−1, i i i而言,若 a [ i ] < a [ i − 1 ] a[i]<a[i-1] a[i]<a[i−1],那么 a [ i ] a[i] a[i]不会对答案产生任何的贡献,因为 a [ i − 1 ] a[i-1] a[i−1]一定可以控制 a [ i ] a[i] a[i],所以能产生贡献的只有 a [ i ] > a [ i − 1 ] a[i]>a[i-1] a[i]>a[i−1]的情况,这种情况两者之间差了多少,我们则需要从 a [ i ] a[i] a[i]补多少,因为 a [ i − 1 ] a[i-1] a[i−1]给 a [ i ] a[i] a[i]的贡献最多只有 a [ i − 1 ] a[i-1] a[i−1]。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> p3;
int mod = 1e9+7;
const int maxv = 4e6 + 5;
// #define endl "\n"
void solve()
{
int n;
cin>>n;
vector<ll> a(n+5);
for(int i=1;i<=n;i++) cin>>a[i];
ll ans=0;
ll sum=0;
for(int i=2;i<=n;i++){
ans+=max(0ll,a[i]-a[i-1]);
}
ans+=a[1]-1;
cout<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
t=1;
cin>>t;
while(t--){
solve();
}
system("pause");
return 0;
}
C. Add, Divide and Floor
题意:
给你一个整数数组
a
1
,
a
2
,
…
,
a
n
a_1, a_2, \dots, a_n
a1,a2,…,an (
0
≤
a
i
≤
1
0
9
0 \le a_i \le 10^9
0≤ai≤109).在一次操作中,你可以选择一个整数
x
x
x (
0
≤
x
≤
1
0
18
0 \le x \le 10^{18}
0≤x≤1018) 并用
a
i
a_i
ai 替换
⌊
a
i
+
x
2
⌋
\lfloor \frac{a_i + x}{2} \rfloor
⌊2ai+x⌋ (
⌊
y
⌋
\lfloor y \rfloor
⌊y⌋ 表示将
y
y
y 舍入为最接近的整数)来替换
i
i
i from
1
1
1 to
n
n
n. 请注意,每次操作都会影响数组中的所有元素。
打印使数组中所有元素相等所需的最小操作数。
如果操作次数小于或等于 n ,则打印每次操作所选择的 x。如果有多个答案,则打印任意一个。
思路:我们贪心的想,每次选择数组的最小值即可,直到数组的最大值等于最小值。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> p3;
int mod = 1e9+7;
const int maxv = 4e6 + 5;
// #define endl "\n"
void solve()
{
int n;
cin>>n;
vector<ll> a(n+5);
for(int i=1;i<=n;i++) cin>>a[i];
int maxv=*max_element(a.begin()+1,a.begin()+1+n);
int minv=*min_element(a.begin()+1,a.begin()+1+n);
int cnt=0;
while(maxv>minv){
cnt++;
maxv=(maxv+minv)/2;
}
cout<<cnt<<endl;
if(cnt<=n){
for(int i=0;i<cnt;i++) cout<<minv<<" ";
cout<<endl;
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
t=1;
cin>>t;
while(t--){
solve();
}
system("pause");
return 0;
}
D. Yet Another Monster Fight
题意:
小V遇到了 n n n 个怪物排成一排,每一个怪物的血量为 a i a_i ai 。小V决定用魔法消灭它们。
在施展魔法时,小V会先选择一个怪物所在的位置 i i i ,作为这个魔法直接攻击的怪物。然后,他会选择魔法的威力 x x x 。
然而,这种魔法十分特殊,会以一定顺序攻击这 n n n 个怪物,第 i i i 个受攻击怪物会受到 x − i + 1 x-i+1 x−i+1 点的伤害。具体来说,这个魔法每次会随机选择一个与被这次魔法攻击过的怪物相邻且没有被攻击的怪物作为对象施展一次攻击。
小V对自己的实力很自信,所以他想知道在他能随意选择第一个攻击位置 i i i 的情况下,最小要用多少的威力 x x x 使得无论魔法沿什么顺序攻击都能杀死所有的怪物。但小V不会这个问题,就把它交给了你。
注:两个怪物视作相邻当且仅当它们之间没有任何其它活着的怪物。
思路:
很好的一个题目,题目是需要我们考虑最坏情况下的最小值,无论以什么顺序攻击都能击杀所有怪物。
我们考虑对于每个怪物而言,杀死其的最坏情况:
对于怪 i ,其最坏情况为,把他右边的怪全部杀完了,然后再来杀怪 i ,那么杀死怪 i 所需要的代价为
a
[
i
]
+
n
−
i
a[i]+n-i
a[i]+n−i
我们同样考虑把他左边的怪全部杀完的情况,那么杀死怪 i 所需要的代价为
a
[
i
]
+
i
−
1
a[i]+i-1
a[i]+i−1。
又因为要求把所有怪全部杀死,所以需要使用前缀和和后缀和去记录到怪 i 为止的最大代价,最后扫描一遍即可。
这种运用前缀和后缀去计算价值/代价的思想需要多加注意。
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> p3;
int mod = 1e9+7;
const int maxv = 4e6 + 5;
// #define endl "\n"
int n;
ll a[N];
vector<ll> pre(N),suf(N);
void solve()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++){
pre[i]=a[i]+n-i;
pre[i]=max(pre[i],pre[i-1]);
}
for(int i=n;i>=1;i--){
suf[i]=a[i]+i-1;
suf[i]=max(suf[i],suf[i+1]);
}
ll ans=2e18;
for(int i=1;i<=n;i++){
ll t=max({a[i],suf[i+1],pre[i-1]});
ans=min(ans,t);
}
cout<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
t=1;
//cin>>t;
while(t--){
solve();
}
system("pause");
return 0;
}
同时,我们可以对这个题进行改编,若我们以最优的杀怪方式去杀,求我们需要的杀死所有怪物的最小代价,那么这题就和广东工业大学的那个火柴人题有异曲同工之妙,我们同样使用优先队列去生成我们的杀怪路径,然后去二分计算即可。