1 条题解

  • 0
    @ 2025-8-24 21:34:17

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar big_news
    away from OI | substandard competitor

    搬运于2025-08-24 21:34:17,当前版本为作者最后更新于2019-06-21 11:36:34,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    纸牌均分问题

    这种题型大概有两种通解:费用流解法(如网络流24题中的负载平衡问题)和数学解法。但是解法一特别容易被卡MLE,能运行的数据范围大概只有n100n\leqslant 100,所以这题来谈谈数学解法。

    分析

    假设有五个书架1,2,3,4,5,其中1号向2号搬5本书,2号向1号搬1本书,1号向5号搬3本书,也可以看作1号向5号搬了3本书,2号向1号搬了-4本书。

    于是可以得出一个结论,即任意一个书架给别的书架的书本数总可以看作一个定值。假设1号只给5号书,2号只给1号书,......,5号只给4号书,且给的书的数量分别为x1,x2,...,x5x_1,x_2,...,x_5,那么x1,x2,...,x5x_1,x_2,...,x_5一定有绝对值最小的确定的值。现在我们要使1i5xi\sum\limits_{1\leqslant i\leqslant 5}|x_i|最小,显然要求出这些“确定的值”。

    数学推理

    头秃系列开始

    设每个书架原先分别有a1,a2,...,ana_1,a_2,...,a_n的书。因为每个书架最终的书本数为1inai÷n\sum\limits_{1\leqslant i\leqslant n}a_i \div n,设这个数为a\overline a,则有以下等式:

    $$\begin{aligned} a_1 = \overline a - x_2 + x_1 \\ a_2 = \overline a - x_3 + x_2 \\ ... \\ a_5 = \overline a - x_1 + x_5 \end{aligned} $$

    移项,得:

    $$\begin{aligned} x_2 = x_1 - (a_1-\overline a) \\ x_3 = x_2 - (a_2 - \overline a) \\ ... \\ x_5 = x_1 - (a_5 - \overline a)\end{aligned} $$

    将前式分别带入后式可得:

    $$\begin{aligned} x_1 = x_1 \\ x_2 = x_1 - (a_1-\overline a) \\ x_3 = x_1 - (a_1 + a_2 - 2\overline a) \\ ... \\ x_5 = x_1 - (a_1+a_2+a_3+a_4 - 4\overline a)\end{aligned} $$

    可知:

    $$x_n = x_1 - (\sum\limits_{1\leqslant 1< n}a_i - (n-1)\times \overline a) $$

    设$c_1 = a_1 - \overline a,c_2 = a_1 + a_2 - 2\overline a,...$,以此类推,可知xn=x1cn1x_n = x_1 - c_{n-1}。同时有递推式ci=ci1+aiac_i = c_{i-1} + a_i - \overline a。这个递推式与xx取值无关,且总有c0=0c_0 = 0,因此可以计算出所有cic_i的值。

    又有x2=x1c1,x3=x1c2,...x_2 = x_1 - c_1,x_3= x_1- c_2,...,则1i5xi\sum\limits_{1\leqslant i\leqslant 5}|x_i|可表示为:

    x1+x1c1+x1c2+...+x1c4|x_1| + |x_1 -c_1| +|x_1-c_2| + ... +|x_1-c_4|

    这也可以看作数轴上每个cic_ix1x_1的距离之和。那么我们就要找一个x1x_1,使得在数轴上它到每个cic_i的距离最小。这个x1x_1即是c1,c2,...,c4c_1,c_2,...,c_4的中位数。

    证明

    先把c1,c2,...,c4c_1,c_2,...,c_4排好序,表示在数轴上,如下图所示。

    二(1)

    任取一x1x_1,则距离之和可以化为$ \text{dist}(c_1,c_4) + \text{dist}(c_2,c_3) +2\times \text{dist}(c_2,x_1)$。其中dist(c1,c4)+dist(c2,c3)\text{dist}(c_1,c_4) + \text{dist}(c_2,c_3)为定值,那么让dist(c2,x1)\text{dist}(c_2,x_1)最小一定会更优一点。它的最小值为00,此时x1x_1选在c2c_2上。

    归纳,可知将x1x_1选在c1 c4c_1\text{~}c_4中的一个点上一定要优一点。

    然后再分别尝试c1,c2,...,c4c_1,c_2,...,c_4这些点,不难发现x1x_1选的越靠中间距离之和越小,故可知x1x_1c1,c2,...,c4c_1,c_2,...,c_4的中位数。

    解决

    那么x1x_1就很好求了,然后就可以推出所有的xx值。第一问就很容易的解决了,第二问只需输出xix_ixi+1-x_{i+1}即可。最后还要再处理一下环。

    注意,当nn为偶数时,两个中位数取哪一个都可以。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    
    #define LL long long
    
    LL read(){ 
        LL s=0,ne=1; char c=getchar();
        for(;c<'0'||c>'9';c=getchar()) if(c=='-') ne=-1;
        for(;c>='0'&&c<='9';c=getchar()) s=((s<<1)+(s<<3))+c-'0';
        return s*ne;
    }
    
    const int CN=1e6+6;
    
    LL n,x1,a[CN],c[CN],_a,rec[CN];
    LL llabs(LL a) {return a>0 ? a:-a;}
    
    int main()
    {
        n=read();
        LL sigma = 0;
        for(int i=1;i<=n;i++) 
            a[i] = read(),sigma += a[i];
        _a = sigma/n; //求平均值 
        
        rec[0] = c[0] = 0;    
        for(int i=1;i<=n;i++)
            rec[i] = c[i] = c[i-1]+a[i]-_a; //递推c[i]
                
        sort(c+1,c+n+1);
        x1 = c[(n+1)/2]; //计算中位数
            
        LL ans=0;
        for(int i=1;i<=n;i++)
            ans += llabs(x1-c[i]); //求代价
        printf("%lld\n",ans);
        for(int i=1;i<n;i++)
            printf("%lld %lld\n",x1-rec[i-1],-(x1-rec[i])); //输出搬运数
        printf("%lld %lld",x1-rec[n-1],-x1); //处理环
        
        return 0;
    }
    
    End- - - - \mathcal{End} - - - -
    • 1

    信息

    ID
    1106
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者