项链
难度:黄金
小码哥最近获得了n颗珍珠,第i颗珍珠拥有一个美观值a;。他现在想把这n颗珍珠以任意顺序排列后串成一串项链,定义一个项链的美观值为相邻珍珠的美观值之差的绝对值之和,即 B e a u t i f u l n e s s = ∑ i = 1 n ∣ a i − a i + 1 ∣ Beautifulness= \sum_{i=1}^n{|a_{i}- a_{i+1}|} Beautifulness=∑i=1n∣ai−ai+1∣
其中
a
i
a_{i}
ai 为重新排列后的项链上的第i颗珍珠的美观值,由于项链是一个环, 我们这里定义
a
n
+
1
=
a
1
a_{n+1}=a_1
an+1=a1。
现在他想知道,在所有可能的情况下得到的项链的最大美观值为多少。请你编写一个程序帮助他计算一下这个值。
样例
输入
4
4 1 2 3
5
1 3 5 2 3
输出
8
10
题解
可知:
B
e
a
u
t
i
f
u
l
n
e
s
s
=
∑
i
=
1
n
∣
a
i
−
a
i
+
1
∣
=
∣
a
1
−
a
2
∣
+
∣
a
2
−
a
3
∣
+
.
.
.
.
+
∣
a
n
−
a
n
+
1
∣
+
∣
a
n
+
1
−
a
1
∣
Beautifulness= \sum_{i=1}^n{|a_{i}- a_{i+1}|} = |a_1 - a_2| + |a_2 - a_3| + .... + |a_n - a_{n+1}| + |a_{n+1} - a_1|
Beautifulness=i=1∑n∣ai−ai+1∣=∣a1−a2∣+∣a2−a3∣+....+∣an−an+1∣+∣an+1−a1∣,
所以:
B
e
a
u
t
i
f
u
l
n
e
s
s
=
±
(
a
1
−
a
2
)
+
±
(
a
2
−
a
3
)
+
.
.
.
.
+
±
(
a
n
−
a
n
+
1
)
+
±
(
a
n
+
1
−
a
1
)
=
2
(
±
a
1
±
a
2
±
.
.
.
.
.
.
±
a
n
±
a
n
+
1
)
Beautifulness= ±(a_1 - a_2) + ±(a_2 - a_3) + .... + ±(a_n - a_{n+1}) +± (a_{n+1} - a_1) = 2(±a_1 ± a_2 ±......± a_n ± a_{n+1})
Beautifulness=±(a1−a2)+±(a2−a3)+....+±(an−an+1)+±(an+1−a1)=2(±a1±a2±......±an±an+1)
B
e
a
u
t
i
f
u
l
n
e
s
s
=
2
∑
i
=
1
n
+
1
±
a
i
Beautifulness = 2\sum_{i= 1}^{n+1}±a_i
Beautifulness=2∑i=1n+1±ai
可以看出Beautifulness包含2n个数,并且2n个数里有n个正数和n和负数,现在问题转化成了:给定n个数,每个数可以出现两次,这些数里面需要有n个正数以及n个负数,求解2n个数和的最大值。
首先将数组
a
i
a_i
ai从小到大排序
不难想到:当n为偶数时,最大值为:
B
e
a
u
t
i
f
u
l
n
e
s
s
=
2
(
∑
i
=
n
/
2
n
a
i
−
∑
i
=
0
n
/
2
−
1
a
i
)
Beautifulness = 2 (\sum_{i = n/2}^{n}a_i - \sum_{i = 0}^{n/2-1}a_i)
Beautifulness=2(i=n/2∑nai−i=0∑n/2−1ai)
当n为奇数时,由于
a
n
+
1
/
2
a_{n+1/2}
an+1/2正负相加,导致结果为0
B
e
a
u
t
i
f
u
l
n
e
s
s
=
2
(
∑
i
=
n
+
1
/
2
n
a
i
−
∑
i
=
0
n
/
2
−
1
a
i
)
Beautifulness = 2(\sum_{i = n+1/2}^{n}a_i - \sum_{i = 0}^{n/2-1}a_i)
Beautifulness=2(i=n+1/2∑nai−i=0∑n/2−1ai)
时间复杂度分析
预排序时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
求和时间复杂度:
O
(
n
)
O(n)
O(n)
总体时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100005;
int a[maxn];
int main( )
{
ios::sync_with_stdio(0);
cin.tie(0);
int n;
cin>>n;
for (int i = 0;i<n;i++)
{
cin>>a[i];
}
sort(a,a+n);
int sum1 = 0,sum2 = 0;
for(int i = 0;i<n/2;i++)
{
sum1 += a[i];
}
if (n%2) n++;
for (int i = n/2;i<n;i++)
{
sum2 += a[i];
}
cout<<2*(sum2 - sum1);
return 0;
}
圈竹鼠
难度:星耀
小码哥和小码弟兄弟俩决定改变饲养环境,给竹鼠更大的自由活动空间。现在竹鼠们在一块无限大的平面草地上,设某一定点坐标为(0, 0),现在每只竹鼠都有自己最喜欢的地点,用坐标 (xi, yi) 表示。兄弟俩想用栅栏围住所有竹鼠喜欢的地点,现在请你计算他们能够围住这些地点的栅栏的最短长度。
格式
输入格式
输入数据的第一行是一个 整数N,表示竹鼠最喜欢的地点数量。
接下来N行每行两个实数xi, yi表示对应地点坐标。
输出格式
输出一行保留两位小数的实数,代表围栏的长度。
样例
输入
4
4 8
4 12
5 9.3
7 8
输出
12.00
题解
采用Andrew求凸包问题的算法,由一个快排
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)和一个遍历找点
O
(
n
)
O(n)
O(n),总体时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)。
快排:将所有点坐标由小到大排序,第一关键字为x,第二关键字为y
算法原理:对于向量
A
B
AB
AB、
A
C
AC
AC,.
若
A
B
×
A
C
>
0
AB×AC>0
AB×AC>0 ,则AB在AC的顺时针方向上
若
A
D
×
A
C
>
0
AD×AC>0
AD×AC>0 ,则AD在AC的逆时针方向上
算法步骤:建立一个存放点的栈
- 先把第一个点入栈
- 从预排序好的数组中顺序依次选点
- 若栈中只有一个点,直接将点入栈中
- 判断该点A与栈顶两个点(B,C)的向量叉乘乘积是否大于0(AC×AB>0)
- 大于0则把A入栈,小于0则从弹栈,重复3~5
上述步骤只能求出整个凸包的一半(下半)。假设下凸包求出有k个点。
需要重复一遍上述流程(修改第2步 为逆序选点、修改第三步 若栈中只有k个点),即可求出整个凸包,凸包边缘的点最终存放在栈中。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100005;
class point
{
public:
double x,y;
bool operator * (point a)
{
return x*a.y - y*a.x;
}
bool operator < (point a)
{
if (x < a.x)
return true;
else return x == a.x && y < a.y;
}
double dis(point a)
{
double dx = (x - a.x) * (x - a.x);
double dy = (y - a.y) * (y - a.y);
return sqrt(dx + dy);
}
static double xmul(point a,point b,point c)
{
return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
};
point a[maxn],b[maxn];
int main( )
{
int n;
scanf("%d",&n);
for (int i = 0;i<n;i++)
{
scanf("%lf %lf",&a[i].x,&a[i].y);
}
sort(a,a+n);
// for (int i = 0;i<n;i++)
// {
// printf("%lf %lf\n",a[i].x,a[i].y);
// }
int cnt = 0;
for(int i=0;i<n;++i)//计算下半个凸包
{
while(cnt >1 && point::xmul(b[cnt -2],b[cnt -1],a[i]) < 0) --cnt;
b[cnt++]=a[i];
}
int k=cnt;
for(int i=n-2;i>=0;--i)//计算上半个凸包
{
while(cnt>k && point::xmul(b[cnt-2],b[cnt-1],a[i]) < 0)
--cnt;
b[cnt++]=a[i];
}
double ans = b[cnt-1].dis(b[0]);
for (int i = 0;i<cnt-1;i++)
{
ans += b[i].dis(b[i+1]);
}
printf("%.2lf",ans);
return 0;
}