今天在看奥数题的时候,突然发现最后一道题和一道oi题是一样的,看看题目之后(半年之前做的了),很巧妙的,只是我想不起来了。
百度很久~很久~还是找不到题解,最后还是想到了,很激动,很激动~~~发一发~~
Problem: English:: 传送~~http://www.spoj.pl/problems/RESTACK/~~ 关键字:: usaco restack
中文::
FJ买了一些干草堆,他想把这些干草堆分成N堆(1<=N<=100,000)摆成一圈,其中第i堆有B_i数量的干草。不幸的是,负责运货的司机由于没有听清FJ的要求,只记住分成N堆摆成一圈这个要求,而每一堆的数量却是A_i(1<=i<=N)。当然A_i的总和肯定等于B_i的总和。FJ可以通过移动干草来达到要求,即使得A_i=B_i,已知把一个干草移动x步需要消耗x数量的体力,相邻两个干草堆之间的步数为1。请帮助FJ计算最少需要消耗多少体力才能完成任务。
很巧啊~~
设Fi为从i到i+1运Fi堆草, Fn则是n~1运的数量。
有题目得到
A1- F1 + Fn = B1
A2- F2 + F1 = B2
A3- F3 + F2 = B3
............
An- Fn + F1= Bn
要是左边一加, 右边一加, 就全没了~~所以整理式子
F1 = A1- B1 + Fn
F2 = A2- B2 + F1
F3 = A3- B3 + F2
..........
Fn=An- Bn +F1
将每一个式子带入到下一个式子里(最后一个式子除外):
F1 = A1- B1 + Fn
F2 = A2- B2 +A1- B1 + Fn
F3 = A3- B3 + A2- B2 +A1- B1 +Fn
..........
Fn=Fn (特殊处理)【这叫特殊吗???】
就可得到每个F关于Fn的式子啦~~~
加上绝对值后再做一些手脚
|F1|= | A1-B1 - (-Fn) |
|F2|= | SUM(Ai- Bi) - (-Fn) | 1<=i<=2
|F3|= | SUM(Ai- Bi) - (-Fn) | 1<=i<=3
.......
|Fn|=|Fn|
可以看出每个sum(&&&)都是可以提前算出来的, 而 | X - Y |的几何意义为数轴上X的点到Y点的距离。
加起来,得到 (设sum(&&&)= Si , -fn= D)
ANS= |S1- D|+ |S2-D| + |S3-D| + ..... + |Sn-1 - D| + |0 - D|
变成了在数轴上求一个点, 到各点的距离之和最小。
众所周知, 这个点就是这组数据中的中位数(若有偶数个, 取两个点的任意一个都可以)。 不明白请举例子或自行百度。
所以中位数即等于-Fn, 于是得到解决。
时间复杂度O(N log N + N)。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
#define N 100005
int S[N];
int n;
int abs(int x){return (x>0)?x:-x;}
int main(){
scanf("%d",&n);
int x,y;
S[0]=0;
for(int i=1;i<=n;i++) scanf("%d%d",&x,&y), S[i]=S[i-1]+x-y;
sort(S+1,S+n+1);
int fn=-S[int(n/2)+1];
long long Ans=0;
for(int i=1;i<=n;i++) Ans+=abs(S[i]+fn);
cout<<Ans<<endl;
return 0;
}
c 新手 , 程序见笑啦~~~
------------------------------------------End---------------------------------------------------