P4995 跳跳!
堆 预处理
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
int x = 0; bool f = false; char ch = getchar();
while(!isdigit(ch)){if(ch == '-') f = true; ch = getchar();}
while(isdigit(ch)){x = x * 10 + ch - '0'; ch = getchar();}
return f ? -x : x;
}
inline void write(ll x){
if (x < 0) x = ~x + 1, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
priority_queue<int, vector<int>, greater<int> > s;//小根堆
priority_queue<int, vector<int>, less<int> > b;//大根堆
ll ans, n, h, now, next;
int main(){
n = read();
for(register int i = 1; i <= n; ++i){
h = read();
b.push(h);
s.push(h);
}
while(n > 1){
now = b.top();
b.pop();
ans += (next - now) * (next - now);
next = now;
now = s.top();
s.pop();
ans += (next - now) * (next - now);
next = now;
n -= 2;
}
if(n){
now = b.top();
b.pop();
ans += (next - now) * (next - now);
}
write(ans);
puts("");
return 0;
}
![](https://i-blog.csdnimg.cn/blog_migrate/3feb19f1cb8f415007612e3becdc75d4.png)
d e q u e deque deque:双端队列的元素可以从两端弹出
用法:
push_back
队尾插入
push_front
队头插入
pop_back
队尾删除
pop_front
队头删除
back
查看尾部
front
查看头部
#include<bits/stdc++.h>
#define ll long long
#define maxn 305
using namespace std;
inline int read(){
int x = 0; bool f = false; char ch = getchar();
while(!isdigit(ch)){if(ch == '-') f = true; ch = getchar();}
while(isdigit(ch)){x = x * 10 + ch - '0'; ch = getchar();}
return f ? -x : x;
}
inline void write(ll x){
if (x < 0) x = ~x + 1, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
deque<ll> d;
ll n, h[maxn], ans;
int main(){
n = read();
for(register int i = 1; i <= n; ++i) h[i] = read();
sort(h + 1, h + n + 1);
for(register int i = 0; i <= n; ++i) d.push_back(h[i]);
while(!d.empty()){
ans += (d.back() - d.front()) * (d.back() - d.front());
d.pop_front();
if(d.empty()) break;//可能出现弹一次就空的情况,需特判一下
ans += (d.front() - d.back()) * (d.front() - d.back());
d.pop_back();
}
write(ans); puts("");
return 0;
}
![](https://i-blog.csdnimg.cn/blog_migrate/fee558de75afd826423639343d226fcf.png)
暴搜
#include<bits/stdc++.h>
#define ll long long
#define maxn 305
using namespace std;
inline int read(){
int x = 0; bool f = false; char ch = getchar();
while(!isdigit(ch)){if(ch == '-') f = true; ch = getchar();}
while(isdigit(ch)){x = x * 10 + ch - '0'; ch = getchar();}
return f ? -x : x;
}
inline void write(ll x){
if (x < 0) x = ~x + 1, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
bool flag[maxn];
ll n, pos, h[maxn], now, mx, ans;
int main(){
n = read();
for(register int i = 1; i <= n; ++i) h[i] = read();
for(register int i = 1; i <= n; ++i){
mx = 0;
for(register int j = 1; j <= n; ++j)
if(!flag[j] && abs(h[j] - now) > mx)
mx = abs(h[j] - now), pos = j;
ans += mx * mx;
flag[pos] = true;
now = h[pos];
}
write(ans); puts("");
return 0;
}
![](https://i-blog.csdnimg.cn/blog_migrate/8843e53a925109b76dc47f9859ec4a3b.png)
数学推导
假 设 不 按 最 大 跳 到 最 小 , 由 h [ n ] 跳 到 h [ s ] , h [ t ] 跳 到 h [ 1 ] 假设不按最大跳到最小,由h[n]跳到h[s],h[t]跳到h[1] 假设不按最大跳到最小,由h[n]跳到h[s],h[t]跳到h[1]
现 在 要 证 明 h [ n ] 跳 到 h [ 1 ] 最 大 , 只 需 固 定 其 它 跳 法 , 然 后 证 明 从 n 到 1 比 从 n 到 s 的 方 法 消 耗 大 即 可 现在要证明h[n]跳到h[1]最大,只需固定其它跳法,然后证明从n到1比从n到s的方法消耗大即可 现在要证明h[n]跳到h[1]最大,只需固定其它跳法,然后证明从n到1比从n到s的方法消耗大即可
( h [ n ] − h [ 1 ] ) 2 + ( h [ t ] − h [ s ] ) 2 > ( h [ n ] − h [ s ] ) 2 + ( h [ t ] − h [ 1 ] ) 2 (h[n]-h[1])^2+(h[t]-h[s])^2>(h[n]-h[s])^2+(h[t]-h[1])^2 (h[n]−h[1])2+(h[t]−h[s])2>(h[n]−h[s])2+(h[t]−h[1])2
⟸ h [ n ] ∗ h [ s ] − h [ n ] ∗ h [ 1 ] + h [ t ] ∗ h [ 1 ] − h [ t ] ∗ h [ s ] > 0 \Longleftarrow h[n]∗h[s]−h[n]∗h[1]+h[t]∗h[1]−h[t]∗h[s]>0 ⟸h[n]∗h[s]−h[n]∗h[1]+h[t]∗h[1]−h[t]∗h[s]>0
⟸ ( h [ n ] − h [ t ] ) ∗ ( h [ s ] − h [ 1 ] ) > 0 \Longleftarrow (h[n]−h[t])∗(h[s]−h[1])>0 ⟸(h[n]−h[t])∗(h[s]−h[1])>0
⟸ h [ n ] > h [ t ] \Longleftarrow h[n]>h[t] ⟸h[n]>h[t], h [ s ] > h [ 1 ] h[s]>h[1] h[s]>h[1]
易得:在石头的 h m a x h_{max} hmax和 h m i n h_{min} hmin中来回跳会使体力值消耗最大
#include<bits/stdc++.h>
#define ll long long
#define maxn 305
using namespace std;
inline int read(){
int x = 0; bool f = false; char ch = getchar();
while(!isdigit(ch)){if(ch == '-') f = true; ch = getchar();}
while(isdigit(ch)){x = x * 10 + ch - '0'; ch = getchar();}
return f ? -x : x;
}
inline void write(ll x){
if (x < 0) x = ~x + 1, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
ll n, h[maxn], ans;
int main(){
n = read();
for(register int i = 1; i <= n; ++i) h[i] = read();
sort(h + 1, h + n + 1);
int now = 0, next = n;
while(now < next){
ans += pow((h[next] - h[now]), 2); ++now;
ans += pow((h[now] - h[next]), 2); --next;
}
write(ans); puts("");
return 0;
}
![](https://i-blog.csdnimg.cn/blog_migrate/693d1f7d997b2fda0f45881e6b473e8d.png)