• 洛谷P2125图书馆书架上的书 题解报告


    题目描述

    图书馆有n个书架,第1个书架后面是第2个书架,第2个书架后面是第3个书架……第n-1个书架后面是第n个书架,第n个书架后面是第1个书架,第i个书架上有b[i]本书。现在,为了让图书馆更美观,WZF神牛让蒟蒻SY搬动书架上的书,使每个书架上的书一样多。由于搬动的书可能会很多,所以蒟蒻SY只能将一个书架上的书搬到与其相邻的两个书架上。那么蒟蒻SY最少搬动几本书呢?

    输入输出格式

    输入格式:

    共2行,第1行1个正整数n,第2行n个非负整数,第i个为b[i]。

    输出格式:

    共n+1行,第1行1个正整数m,表示蒟蒻SY最少搬动m本书,之后n行(即第2行至第n+1行)每行2个整数,第i行有两个整数af[i]和ab[i],分别表示蒟蒻SY要将第i个书架上的af[i]本书和ab[i]本书分别搬到它前面的一个书架上和它后面的一个书架上。

    输入输出样例

    输入样例#1:
    5
    15 7 11 3 14
    
    输出样例#1:
    12
    2 3
    -3 0
    0 1
    -1 -6
    6 -2
    

    说明

    n<=5000001(为保证有唯一解,n必为奇数),b[i]<= 21474803648(蒟蒻SY:俺当初一看到这儿就想哭。)

    若af[i]为负数,则说明蒟蒻SY要把第i个书架前面的那个书架上的-af[i]本书搬到第i个书架上。

    同理,若ab[i]为负数,则说明蒟蒻SY要把第i个书架后面的那个书架上的-ab[i]本书搬到第i个书架上。





    题解:

    在输入后我们统计求得最终每个书架上的数的数量m

    设xi为第i个书架上的书,令xi-=m

    我们设ai表示第i个书架向下一个书架移动了几本书

    那么移动数ans=|a1|+|a2|+|a3|+|a4|+......+|an| 求最小值



    当然那么多的变量不好找关系

    由于每个书架上的书最终为m【自减m后最终为0】,那么有xi+a[i-1]-a[i]=0

    这样子就有

    a1=a1

    a2=a1+x2

    a3=a2+x3=a1+x2+x3

    a4=a3+x4=a1+x2+x3+x4

    ......

    那么ans=|a1|+|a1+x2|+|a1+x2+x3|+|a1+x2+x3+x4|+......

    由于xi都为已知的常数,那么我们可以写成这样一个形式:

    ans=|a1|+|a1+k1|+|a1+k2|+|a1+k3|+|a1+k4|+......

    那么问题就转化成了如何求这堆绝对值的最小值


    我们可以数形结合:想一想绝对值的集合意义是什么?

    对!就是到原点的距离

    我们把每个绝对值里的东西看作数轴上的一个点,那么这些点与a1的相对位置不变

    也就是说我们在尝试改变a1的位置以谋求所有点到原点的距离和最小

    当我们把a1向左移时,原点左边的点远离原点,原点左边的点接近原点,也就是说,【因为点数为奇数】当所有点的中位点处于原点时,ans就是最小的


    这个时候问题就变得很简单啦,求出算出关于x的前缀和,然后排序求出中间点

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define LL long long int
    using namespace std;
    const int maxn=5000005,INF=200000000;
    
    inline LL read(){
    	LL out=0,flag=1;char c=getchar();
    	while(c<48||c>57) {if(c=='-') flag=-1;c=getchar();}
    	while(c>=48&&c<=57) {out=out*10+c-48;c=getchar();}
    	return out*flag;
    }
    
    LL A[maxn],sum[maxn],temp[maxn],N,tot=0;
    
    int main()
    {
    	N=read();
    	for(int i=1;i<=N;i++) tot+=(A[i]=read());
    	tot/=N;
    	A[1]-=tot;
    	for(int i=2;i<=N;i++){
    		A[i]-=tot;
    		temp[i]=sum[i]=sum[i-1]+A[i];
    	}
    	sort(temp+1,temp+1+N);
    	LL mid=-temp[(N>>1)+1],ans=0;
    	for(int i=1;i<=N;i++) ans+=abs(mid+sum[i]);
    	printf("%lld
    ",ans);
    	for(int i=1;i<=N;i++){
    		printf("%lld %lld
    ",-(mid+sum[i-1 ? i-1:N]),mid+sum[i]);
    	}
    	return 0;
    }
    

    这道题还是给了我们很多的思路,尤其是绝对值的几何意义,这可以给我们解题更多的启发


  • 相关阅读:
    挺好用的SQLSERVER数据库自动备份工具SQLBackupAndFTP(功能全面)
    SQLSERVER中的鬼影索引
    SQLSERVER NULL和空字符串的区别 使用NULL是否节省空间
    SQLSERVER中NULL位图的作用
    SQLSERVER到底能识别多少个逻辑CPU?
    不正常关机引起的数据库置疑
    如何在大型的并且有表分区的数据库中进行DBCC CHECKDB操作
    索引视图是否物理存储在数据库中以及使用索引视图的一些见解
    Oracle非重要文件恢复,redo、暂时文件、索引文件、password文件
    最大匹配、最小顶点覆盖、最大独立集、最小路径覆盖(转)
  • 原文地址:https://www.cnblogs.com/Mychael/p/8282886.html
Copyright © 2020-2023  润新知