Time cost: 35min
环形均分纸牌
我们再回顾一下均分纸牌
1 scanf("%d",&n);
2 for(i = 1; i <= n; i++)
3 {
4 scanf("%d",a + i);
5 sum += a[i];
6 }
7 double ave = sum / (double)n;
8 int tim = n;
9 sum = 0;
10 for(int i = 1; i <= n; i++)
11 {
12 sum += a[i];
13 if(sum / (double)i == ave) --tim;
14 }
就这么个东西
数组元素减掉平均值之后求前缀和
前缀和为0的时候就说明不用从左边移牌到右边 次数-1
这个题虽然问的是最小传递数 但是效果一样
开始可以考虑枚举断开的点
如果在k点断开 那么就相当于从k开始求前缀和
但是每遍求前缀和复杂度会爆炸O(n^2)
所以可以从1开始求的前缀和推出来后面的就是
n点的前缀和 S[n]-S[k]
1点的前缀和 S[1]+S[n]-S[k]
(就写这两个应该就知道了)
这样就可以O(n^2) 但是还是会爆炸
然后考虑最后的答案就是所有前缀和求和
也就是
考虑数轴上从1到n 每个S[i]位置上有一个点
求最短距离和
是不是看到了种树问题?
所以就取最中间的点就OK
复杂度O(n)+O(sort)
Code:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define rep(i,a,n) for(int i = a;i <= n;++i) 5 const int N = 1000006; 6 using namespace std; 7 typedef long long ll; 8 ll n,ave,ans; 9 ll a[N],s[N]; 10 int main() { 11 scanf("%lld",&n); 12 rep(i,1,n) scanf("%lld",a+i),ave += a[i]; 13 ave /= n; 14 rep(i,1,n) a[i] -= ave,s[i] = s[i-1] + a[i]; 15 sort(s+1,s+n+1); 16 ave = s[n+1 >> 1]; 17 rep(i,1,n) ans += abs(ave - s[i]); 18 printf("%lld ",ans); 19 return 0; 20 }