思维题(转化思想)

https://www.nowcoder.com/acm/contest/90/C

题意:一共有n位同学,他们都按照编号顺序坐在一个圆桌旁。第i位同学一开始有a[i]个硬币,希望使得每位同学手上的硬币变成相同的数目。每一秒钟,有且仅有一位同学可以把自己手上的一枚硬币交给另一位同学,其中这两位同学中间必须间隔k位同学,问最少几秒后所有同学手上的有相同数量的硬币。

题解:(见白书P5)

首先,最终每个小朋友的糖果数量可以计算出来,等于糖果总数除以n,用ave表示。
假设标号为i的小朋友开始有Ai颗糖果,Xi表示第i个小朋友给了第i-1个小朋友Xi颗糖果,如果Xi<0,说明第i-1个小朋友给了 第i个小朋友Xi颗糖果,X1表示第一个小朋友给第n个小朋友的糖果数量。 所以最后的答案就是ans=|X1| + |X2| + |X3| + ……+ |Xn|。
对于第一个小朋友,他给了第n个小朋友X1颗糖果,还剩A1-X1颗糖果;但因为第2个小朋友给了他X2颗糖果,所以最后还剩A1-X1+X2颗糖果。根据题意,最后的糖果数量等于ave,即得到了一个方程:A1-X1+X2=ave。
同理,对于第2个小朋友,有A2-X2+X3=ave。最终,我们可以得到n个方程,一共有n个变量,但是因为从前n-1个方程可以推导出最后一个方程,所以实际上只有n-1个方程是有用的。
尽管无法直接解出答案,但可以用X1表示出其他的Xi,那么本题就变成了单变量的极值问题。
对于第1个小朋友,A1-X1+X2=ave  ->  X2=ave-A1+X1 = X1-C1(假设C1=A1-ave,下面类似)
对于第2个小朋友,A2-X2+X3=ave  ->  X3=ave-A2+X2=2ave-A1-A2+X1=X1-C2
对于第3个小朋友,A3-X3+X4=ave  ->  X4=ave-A3+X3=3ave-A1-A2-A3+X1=X1-C3
……
对于第n个小朋友,An-Xn+X1=ave。
  我们希望Xi的绝对值之和尽量小,即|X1| + |X1-C1| + |X1-C2| + ……+ |X1-Cn-1|要尽量小。注意到|X1-Ci|的几何意义是数轴上的点X1到Ci的距离,所以问题变成了:给定数轴上的n个点,找出一个到他们的距离 之和尽量小的点,而这个点就是这些数中的中位数。
 
 1 //#include<bits/stdc++.h>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <cstdio>
 5 #include <cstring>
 6 #include <string>
 7 #include <cmath>
 8 #include <cstdlib>
 9 #include <queue>
10 #include <stack>
11 #include <map>
12 #include <vector>
13 #include <set>
14 
15 using namespace std;
16 typedef long long LL;
17 typedef pair<int, int> pii;
18 const int INF = 0x7fffffff;
19 const int maxn = 1e6 + 10;
20 const double eps = 1e-8;
21 const int MAXN = 1e5 + 10;
22 int prime[MAXN+1];
23 LL a[maxn];
24 bool vis[maxn];
25 LL sum[maxn];
26 int n, k;
27 LL ave;
28 
29 LL get_sum(vector<LL> v) {
30     for(int i = 0; i < v.size(); i++) {
31         sum[i+1] = sum[i] + v[i] - ave;
32     }
33     sort(sum, sum + v.size());
34     LL mid = sum[v.size()/2];
35     LL cnt2 = 0;
36     for(int i = 0; i < v.size(); i++)
37         cnt2 += abs(mid - sum[i]);
38     return cnt2;
39 }
40 
41 LL solve() {
42     cin >> n >> k;
43     LL cnt = 0;
44     bool flag = false;
45     for(int i = 0; i < n; i++) {
46         cin >> a[i];
47         cnt += a[i];
48     }
49     if(cnt % n != 0) return -1;
50     ave = cnt / n;
51     for(int i = 0; i < n; i++)
52         if(a[i] != ave) flag = true;
53     if(!flag) return 0;
54     if(k == n) return -1;
55     k++;
56     LL ans = 0;
57     for(int i = 0; i < n; i++) {
58         if(vis[i]) continue;
59         vector<LL> v;
60         int j = i;
61         LL cnt1 = 0;
62         while(!vis[j]) {
63             vis[j] = true;
64             v.push_back(a[j]);
65             j = (j + k) % n;
66             cnt1 += a[j];
67         }
68         if(cnt1 % ave != 0 || cnt1 / ave != v.size())
69             return -1;
70         ans += get_sum(v);
71         v.clear();
72     }
73     return ans;
74 }
75 
76 int main(){
77 #ifdef local
78     freopen("case.in", "r", stdin);
79 #endif
80     ios::sync_with_stdio(false);
81     cin.tie(0);
82     LL ans = solve();
83     if(ans == -1) cout << "gg" << endl;
84     else cout << ans << endl;
85     return 0;
86 }

 

posted @ 2018-03-26 23:17  Sissi_hss  阅读(473)  评论(0编辑  收藏  举报