C. Recycling Bottles
题意:
在网格上有n个瓶子,现在有两个人A和B,他们有自己的起始位置,还有一个垃圾桶的位置,求捡完瓶子之后两个人走的最短距离是多少。捡瓶子的步骤是:先去捡瓶子,然后扔到垃圾桶。
思路:
我们先假设把所有的瓶子都捡了,记录一个答案 ans, 代表要走多少路,
然后我们找出来从 A 的出发点走会减少多少距离, 从 B 的出发点走会减少多少距离。
所以我们只需要找到两个距离的最大值就可以了。
加上一个特判。 当 n == 1 的时候,
首先可以肯定的是, 一定有一个人去捡瓶子,另外一个人减少的距离如果是正数,那么可以用 ans 减去,如果减少的距离是负数,那这个人就不用去捡瓶子了。
反思:
刚做这个题的时候,我想的是从 A 点出发,找一个离A 最近的瓶子,从 B 出发找一个离 B 最近的瓶子,然后发现样例都不能过。
然后苦思冥想才想着反过来做。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+100;
void dbg() {cout << endl;}
template<typename T, typename... A> void dbg(T a, A... x) {cout << a << ' '; dbg(x...);}
#define logs(x...) {cout << #x << " -> "; dbg(x);}
struct node{
int id;
double val;
}a[N],b[N],t[N];
int x[N],y[N],ax,ay,bx,by,tx,ty,n;
double dis(int x, int y, int xx, int yy){
return sqrt(1ll*(x-xx)*(x-xx) + 1ll*(y -yy)*(y-yy));
}
bool cmp(node A, node B){
return A.val > B.val;
}
double ans;
int main(){
scanf("%d%d%d%d%d%d",&ax,&ay,&bx,&by,&tx,&ty);
scanf("%d",&n);
for (int i = 0; i < n; ++i)
scanf("%d%d",&x[i],&y[i]);
for (int i = 0; i < n; ++i){
t[i].id = i;
t[i].val = dis(tx, ty, x[i],y[i]);
ans += t[i].val * 2;
}
for (int i = 0; i < n; ++i){
a[i].id = i;
b[i].id = i;
a[i].val = t[i].val - dis(ax,ay,x[i],y[i]);
b[i].val = t[i].val - dis(bx,by,x[i],y[i]);
}
sort(a, a + n, cmp);
sort(b, b + n, cmp);
if (n == 1){
if (a[0].val > b[0].val){
ans -= a[0].val;
} else{
ans -= b[0].val;
}
printf("%.10lf\n",ans);
return 0;
}
double tmp1, tmp2;
if (a[0].id != b[0].id){
tmp1 = a[0].val;
if (b[0].val > 0) tmp1 += b[0].val;
tmp2 = b[0].val;
if (a[0].val > 0) tmp2 += a[0].val;
}else{
tmp1 = a[0].val;
if (b[1].val > 0) tmp1 += b[1].val;
tmp2 = b[0].val;
if (a[1].val > 0) tmp2 += a[1].val;
}
if (tmp1 < tmp2) swap(tmp2, tmp1);
ans -= tmp1;
printf("%.10lf\n",ans);
return 0;
}
D. Robin Hood
题意:
有一些人,每个人都有一些金币,现在要求每次最富的人给最穷的人一个金币,直到 k天,问最富和最穷的金币差,最终的金币差是一定的。
思路:
我们可以看到,这个题的金币数量是很多的,但是他的人数并不多,所以我们从人数入手,解决这个问题。
首先把每个人的金币数量排个序, 从小到大排序,
然后从小到大增加 k 个金币, 看看最穷的人有多少金币 mx,
然后从大到小减少 k 个金币, 看看最富的人有多少金币 mn。
如果 mn > mx 那么答案就是 mn - mx。
否则答案 不是 0 就是 1, 这个用 sum % n 的结果来判断。 ‘
需要注意的是 mn mx 的初始话, 以及 mx mn 的更新。
反思:
刚开始做这个题的时候,没有想法, 后来发现这个题就是把最大的移到最小的上面去。以前好像做过这样的题。
刚开始的时候,我还想着二分, 二分最富的人最终会剩下多少钱。然后不了了之。
这样好像就是个套路题, 从小到大排序,然后从小到大,一点一点增加金币。
That’s all
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+100;
int a[N],n,m,k,c[N];
long long sum,mx,mn;
void dbg() {cout << endl;}
template<typename T, typename... A> void dbg(T a, A... x) {cout << a << ' '; dbg(x...);}
#define logs(x...) {cout << #x << " -> "; dbg(x);}
int main(){
scanf("%d%d",&n,&k);
for (int i = 1; i <= n; ++i){
scanf("%d",&c[i]);
sum += c[i];
}
sort(c+1, c + n + 1);
mx = c[1];
mn = c[n];
long long tmp = 0;
for (int i = 1; i < n; ++i){
if (tmp + 1ll*i * (c[i+1] - c[i]) <= k){
tmp += 1ll* i * (c[i+1] - c[i]);
} else{
tmp = k - tmp;
mx = c[i] + (tmp / i);
break;
}
mx = c[i+1];
}
tmp = 0;
for (int i = n - 1; i >= 1; --i){
if (tmp + 1ll * (n - i) * (c[i+1] - c[i]) <= k){
tmp += 1ll * (n - i) * (c[i+1] - c[i]);
} else{
tmp = k - tmp;
mn = c[i+1] - (tmp / (n - i));
break;
}
mn = c[i];
}
if (mn > mx){
printf("%lld\n",mn - mx);
} else {
if (sum % n) puts("1"); else puts("0");
}
return 0;
}