acwing 104.货仓选址
https://www.acwing.com/problem/content/106/
题意:需要在竖轴上选一个点,使该点到其他给出点的距离之和最小。将其抽象为数学公式$\left | x - c_1 \right |+\left | x-c_2 \right |+\left | x-c_3 \right |+\cdot \cdot \cdot \left | x-c_k \right |$,求该公式的最小值。
可以知道,该公式的最小值就是取$c_1, c_2, c_3,\cdot \cdot \cdot c_k$的中位数。
证明:
当只有一个点的时候,选在该点肯定为最小,当有两个点的时候,选在两个点中间的任何一个位置都为最小,当有三个点的时候,选在中间那个点的位置。我们将每个点两两分组。
①当$k$为奇数时,$x_1$和$x_k$一组,$x_2$和$x_{k -1}$一组,最后剩$x_{\frac{k + 1}{2}}$单独一组,可以知道,选择每一组中间的点都是最小的。而$x_{\frac{k + 1}{2}}$这一组要选在这个点上最小,所以选在$x_{\frac{k + 1}{2}}$上的时候,满足该组的值最小,也满足其他组的值最小,所以总和最小。
②当$k$为偶数时,每一组都是两两配对,选择每组中间的位置就最小值,而最靠近中心的两个点的那个区间,选择任意一个在该区间内的点,都可以做到使得每一组的答案最小。
思路:读入一个$a$数组,排序,找出中位数,用所有数减去中位数的绝对值相加即为答案。
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 5 using namespace std; 6 7 const int N = 1e5+10; 8 int a[N]; 9 int n; 10 11 int main(){ 12 cin >> n; 13 for(int i = 0 ; i < n ; i ++)cin >> a[i]; 14 15 sort(a, a + n); 16 int c = a[n / 2]; 17 18 int res = 0; 19 for(int i = 0 ; i < n ; i ++)res += abs(a[i] - c); 20 21 cout << res << endl; 22 return 0; 23 }
acwing 122.糖果传递
https://www.acwing.com/problem/content/description/124/
假设只向前方进行传递,设a_1传递的个数为x_1, 画出如图:
根据图,我们可以知道我们要求的就是公式$\left |x_1 \right |+\left | x_2 \right |+\cdot \cdot \cdot \left | x_n \right |$的最小值,而且我们可以写出一组公式
$\left\{\begin{matrix}a_1-x_1+x_2 = \bar{a}
& & & & \\ a_2-x_2+x_3=\bar{a}
& & & & \\ a_3-x_3+x_4=\bar{a}
& & & & \\ \cdot \cdot \cdot
& & & & \\a_n-x_n+x_1=\bar{a}
\end{matrix}\right.$
化简该公式:
$\left\{\begin{matrix}x_1=x_1 - 0
& & & \\ x_2=x_1-(a_1-\bar{a})
& & & \\ x_3=x_1-(a_1+a_2-2 \bar{a})
& & & \\ x_4 = x_1-(a_1+a_2+a_3 - 3\bar{a})
& & & \\ \cdot \cdot \cdot
& & & \\x_n=x_1-(a_1+a_2+\cdot \cdot \cdot a_{n-1}-(n-1)\bar{a})
\end{matrix}\right.$
可以看出,$x_1$后方的值可以看做常数项,将其设为$c$,
可以将公式再次化为:
$\left\{\begin{matrix}x_1=x_1 -c_1
& & & \\ x_2=x_1-c_2
& & & \\ x_3=x_1-c_3
& & & \\ x_4 = x_1-c_4
& & & \\ \cdot \cdot \cdot
& & & \\x_n=x_1-c_n
\end{matrix}\right.$
这样,题目就从求$\left |x_1 \right |+\left | x_2 \right |+\cdot \cdot \cdot \left | x_n \right |$的最小值,变成了求$\left |x_1 -c_1 \right |+\left | x_1-c_2 \right |+\cdot \cdot \cdot \left | x_1-c_n \right |$的最小值。转换为了求绝对值不等式的最小值。
思路:用递推的方式将数组$c$处理出,然后排序。循环与中位数相减将绝对值相加即为答案。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 6 using namespace std; 7 8 typedef long long LL; 9 10 const int N = 1000010; 11 12 int n; 13 int a[N]; 14 LL c[N]; 15 16 int main() 17 { 18 scanf("%d", &n); 19 for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]); 20 21 LL sum = 0; 22 for (int i = 1; i <= n; i ++ ) sum += a[i]; 23 24 LL avg = sum / n; 25 for (int i = n; i > 1; i -- ) 26 { 27 c[i] = c[i + 1] + avg - a[i]; 28 } 29 c[1] = 0; 30 31 sort(c + 1, c + n + 1); 32 33 LL res = 0; 34 for (int i = 1; i <= n; i ++ ) res += abs(c[i] - c[(n + 1) / 2]); 35 36 printf("%lld\n", res); 37 38 return 0; 39 }
acwing 105.七夕祭
https://www.acwing.com/problem/content/107/
分析题意知道,这道题目有一个性质是,只会改变相邻的两个数的位置,因此我们交换两个数,只会改变一行的喜爱小摊或者一列的喜爱小摊,而不会同时改变行和列的喜爱小摊,这样,我们就可以将这道题目分成两个部分,一部分是求行的最少次数,一部分是求列的最少次数。这样原问题就从二维的问题拆成了一维的问题,等于在竖直方向上和水平方向上做糖果传递。
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 5 using namespace std; 6 7 typedef long long LL; 8 9 const int N = 1000010; 10 11 int n, m, T; 12 int col[N], row[N]; 13 int s[N], c[N]; 14 15 LL solve(int n, int r[]) 16 { 17 memset(s, 0, sizeof s); 18 memset(c, 0 ,sizeof c); 19 20 for(int i = 1 ; i <= n ; i ++)s[i] = s[i - 1] + r[i]; 21 22 if(s[n] % n)return -1; 23 24 int avg = s[n] / n; 25 26 for(int i = 2 ; i <= n ; i ++)c[i] = s[i - 1] - (i - 1) * avg; 27 28 sort(c + 1, c + n + 1); 29 30 LL sum = 0; 31 for(int i = 1 ; i <= n ; i ++)sum += abs(c[i] - c[(n + 1) / 2]); 32 33 return sum; 34 } 35 36 int main(){ 37 38 cin >> n >> m >> T; 39 40 while(T --) 41 { 42 int x, y; 43 cin >> x >> y; 44 row[x] ++, col[y] ++; 45 } 46 47 LL one = solve(n, row); 48 LL two = solve(m, col); 49 50 if(one != -1 && two != -1)cout << "both" << " " << one + two << endl; 51 else if(one != -1)cout << "row" << " " << one; 52 else if(two != -1)cout << "column" << " " << two; 53 else cout << "impossible" << endl; 54 55 return 0; 56 }