M.Windblume Festival
题意
有最多’1e6’名玩家,围成一个圈,每名玩家对应一个值
a
r
r
[
i
]
arr[i]
arr[i],每次删除相邻两个中后一个,并把前一个值减去后一个的值(
a
r
r
[
(
i
m
o
d
k
)
+
1
]
arr[(i mod k)+1]
arr[(imodk)+1],
k
k
k为剩余玩家数)。
求最终剩余可能的最大值。
思考
考虑玩家对应值 a r r [ i ] arr[i] arr[i]的正负情况:
1.有正有负
先将两个负数间的正数减到负数上,并留下一个正数
在用剩下的一个正数减去所有负数即可,故结果为:
∑
∣
a
r
r
[
i
]
∣
\sum |arr[i]|
∑∣arr[i]∣
2.同为正
这时我们考虑构造出有正有负的情况,那要如何让损失降到最小呢?
我们知道,如果全都是正数,只要构造出一个负数,就可以得到结果为 ∑ ∣ ( n e w ) a r r [ i ] ∣ \sum |(new)arr[i]| ∑∣(new)arr[i]∣了。
由于我们只能让相邻两个数前减后得出负数,要将损失降至最小,只要遍历
k
(
人
数
)
k(人数)
k(人数)得出:
M
i
n
L
o
s
s
=
m
i
n
(
∣
a
r
r
[
i
]
∣
+
∣
a
r
r
[
i
+
1
]
∣
−
∣
a
r
r
[
i
]
−
a
r
r
[
i
+
1
]
∣
)
MinLoss = min(|arr[i]|+|arr[i+1]|-|arr[i]-arr[i+1]|)
MinLoss=min(∣arr[i]∣+∣arr[i+1]∣−∣arr[i]−arr[i+1]∣)
那么:
a
n
s
w
e
r
=
∑
∣
a
r
r
[
i
]
∣
−
M
i
n
L
o
s
s
answer = \sum |arr[i]| - MinLoss
answer=∑∣arr[i]∣−MinLoss
3.同为负
只要加上绝对值后当正数处理即可。
代码实现
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6 + 7;
long long ans = 0;
int n = 0, times = 0;
int arr[N]; // 存放玩家对应的值
void fig(){ // 计算绝对值之和
for(int i=1;i<=n;i++)
ans+=abs(arr[i]);
}
void poss();
void negg(){ // 全负变为全正来做
for (int i = 1; i<=n; i++){
arr[i] = -arr[i];
}
poss();
}
void poss(){
int temp=2e9+7;
for(int i=1;i<n;i++)
if(arr[i]-arr[i+1]<=0) // 遍历求最小损失
temp=min(temp,arr[i]+arr[i+1]-abs(arr[i]-arr[i+1]));
if(arr[n]-arr[1]<=0) temp=min(temp,arr[n]+arr[1]-abs(arr[n]-arr[1]));
fig();
ans-=temp;
}
void wtf(){
cin >> n;
int pos = 0, neg = 0;
for (int i = 1; i <= n; i++){
cin >> arr[i];
if(arr[i]<=0) // 是否有负数
neg = 1;
if(arr[i] >= 0) // 是否有正数
pos = 1;
}
if(n==1){
cout << arr[1] << "\n";
return;
}
ans = 0;
if(pos && neg)
fig();
else if(neg)
negg();
else
poss();
cout << ans << "\n";
}
int main(){
ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> times;
while(times--){
wtf();
}
return 0;
}
完整题面