原题
魔法训练(train.cpp)
【题目描述】
ZEY做梦梦到自己穿越到了一个魔法世界。但是他却不知道运用魔法的技巧,于是他找到了隐居的魔法大师学技巧。
大师一挥手,地上就升起了一排石柱,这些石柱的高度从右往左正好是
1
,
2
,
3
,
.
.
.
.
.
.
,
n
1,2,3,......,n
1,2,3,......,n 。大师让ZEY运用魔法将两个石柱交换位置,并规定了得分标准:当ZEY的所有交换操作结束后,对于任意第
i
i
i 个石柱和第
j
j
j 个石柱,只要满足
i
<
j
i<j
i<j 且
h
[
i
]
>
h
[
j
]
h_{[i]}>h_{[j]}
h[i]>h[j] ,就可以的一分。ZEY发现,每交换一次石柱就会消耗
1
1
1 点魔法,而他最多只有
m
m
m 点魔法,ZEY想知道他最多能得多少分。
【输入说明】
输入文件名为 train.in
输入为两个整数,分别是
n
n
n 和
m
m
m ,两个整数用空格隔开。
【输出说明】
输出文件名为 train.out
输出一个整数,表示ZEY的最高得分。
输入样例1:
4 1
输出样例1:
5
输入样例2:
4 10
输入样例2:
6
【样例说明】
对于样例1,交换
1
1
1 和
4
4
4 ,石柱变为
4
,
3
,
2
,
1
4,3,2,1
4,3,2,1 ,可以得
5
5
5 分。
对于样例2,魔力足够将其换为
4
,
3
,
2
,
1
4,3,2,1
4,3,2,1 ,得
6
6
6 分。
【数据范围】
对于
30
30%
30 的数据,
1
≤
n
≤
100
1\le n\le 100
1≤n≤100 ,
1
≤
m
≤
100
1\le m\le 100
1≤m≤100 。
对于
100
100%
100 的数据,
1
≤
n
≤
1
0
9
1\le n\le 10^9
1≤n≤109 ,
1
≤
n
≤
1
0
9
1\le n\le 10^9
1≤n≤109 。
题解:
本题时间复杂度正解:
O
(
N
)
O(N)
O(N) 。
本题算法正解:不需要循环,递归。只需要1次判断。
本题算法标签:贪心。
本题贪心思路:每一次交换首尾。
证明方式:
对于数列:
1
,
2
,
3
,
.
.
.
.
.
.
,
i
,
i
+
1
,
i
+
2
,
.
.
.
.
.
.
,
j
,
j
+
1
,
.
.
.
.
.
.
n
1,2,3,......,i,i+1,i+2,......,j,j+1,......n
1,2,3,......,i,i+1,i+2,......,j,j+1,......n 中,当交换
i
i
i 和
j
j
j 时,得到的数列为:
1
,
2
,
3
,
.
.
.
.
.
.
,
j
,
i
+
1
,
i
+
2
,
.
.
.
.
.
.
i
,
j
+
1
,
j
+
2
,
.
.
.
.
.
.
n
1,2,3,......,j,i+1,i+2,......i,j+1,j+2,......n
1,2,3,......,j,i+1,i+2,......i,j+1,j+2,......n,得分段为
i
−
j
i- j
i−j 中,每交换一次得分为:
2
∗
(
j
−
i
)
−
1
2 * (j-i)-1
2∗(j−i)−1 分。要让此方法尽可能的大,只有让
i
i
i 尽可能小,
j
j
j 尽可能大。
代码实现方式:
- 循环
O ( M ) O(M) O(M) 的算法会超时。洛谷评测机很快,所以可以得90分,但是在CCF上可能得不了高分,所以这个方法放弃。 - 等差数列
详见代码:
#include<cstdio>
signed main(){
freopen("train.in","r",stdin);
freopen("train.out","w",stdout);
long long n,m;
scanf("%lld%lld",&n,&m);
long long ans=0;
if(m>=(n>>1))ans=((n-1)*n)>>1;//特判,当m大于2/n时,直接用等差数列即可。
else ans=((2*(n-1)-1+2*(n-2*m+1)-1)*m)>>1;
printf("%lld",ans);
return 0;
}