题解 UVA11300 【Spreading the Wealth】

环形均分纸牌问题应该不少人都很熟悉了,而且题解区写的也比较全了......

我这篇题解主要是介绍一个新的STL——nth_element

以及解答几个其他题解里面有应用但是没有注释的问题。(比如说我第一次看就十分懵逼)

如果从第i个人开始转手,那么他们的前缀和分别为

s[i+1]-s[i]

s[i+2]-s[i]

......

s[n]-s[i]

s[1]+s[n]-s[i]

......

s[i]+s[n]-s[i]

因为是均分,所以满足s[n]恒等于0,所以加和可得最小数量:$\sum_{i=1}^n$abs(s[i]-s[k])

(为什么数量是前缀和相加呢,因为当轮到自己的时候前面应该已经均分过了,将自己和前面看作一个整体,而这时就必须要下一个进行交换,使得自己的体系平均下来和均值相等,而这个和均值相差的值,自然就是abs(前缀和)了,所以最后我们将它累加,就是答案。)

显然当s[k]取中位数时数量最小。
(而为什么有这个显然呢,借用别的dalao的话来说就是:原因各位可以想象将 S[i] 投影到一个坐标平面内。然后我们用一条线去扫,点到线的距离之和就是上面的式子的最小值。从中位数的位置变化到靠下的位置或是靠上的位置,都会使某一部分点的距离增大。)

STL中的nth_element()方法的使用:

通过调用nth_element(start, start+n, end) 方法可以使第n大元素处于第n位置(从0开始,其位置是下标为 n的元素),并且比这个元素小的元素都排在这个元素之前,比这个元素大的元素都排在这个元素之后,但不能保证他们是有序

但是明明已经有了sort排序,为什么要用这个呢——因为这个的时间复杂度比sort优,是log(n)级别的,显然更快一点。

我的代码中将每一项都减去了平均值,其实减不减无所谓,减掉反而又有一点多此一举了.......

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define MAXN 1000010
using namespace std;
int n;
long long a[MAXN],s[MAXN],sum=0,ans=0;
int main(){
    while(scanf("%d",&n)!=EOF)
    {
    //scanf("%d",&n);
    memset(a,0,sizeof(a));
    memset(s,0,sizeof(s));
    sum=0;  ans=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        sum+=a[i];
    }
    sum=sum/n;
    for(int i=1;i<=n;i++)
    {
        a[i]-=sum;
        s[i]=s[i-1]+a[i];
    }
    int mid=(n+1)/2;
    //中位数的位置
    nth_element(s+1,s+mid,s+1+n);
    /*上文中有提到,所以中间这个加上的值就是表示从0开始,安排好第mid位为中位数,因此不必+1
    但是由于我们迭代器使用的是数组的位置,所以前后位置限定还是要+1的*/
    int cur=s[mid];
    for(int i=1;i<=n;i++)
        ans+=abs(s[i]-cur);
    printf("%lld\n",ans);
}
    return 0;
}

话说环形均分纸牌的题目还真的不少,

这不是四倍经验么2333:

(大家如果觉得掌握的不好可以去AC这几道题,基本上都差不多,就是开long long和不开long long 的区别......,哦对了,输入格式也有一点点不一样,注意改一下)

P4016

P2512

P3156

猜你喜欢

转载自www.cnblogs.com/fengxunling/p/9391270.html
今日推荐