首页 > 试题广场 >

画展布置

[编程题]画展布置
  • 热度指数:1927 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
\hspace{15pt}展厅共有 N 幅画作,其艺术价值为整数 A_1,A_2,\dots ,A_N。策展人需选出其中 M 幅依次摆放。设选出后排成一列的价值为 B_1,\dots ,B_M,定义一个画展的不和谐度 L 满足

L\;=\;\sum_{i=1}^{M-1}\bigl|B_{i+1}^2-B_i^2\bigr|.

\hspace{15pt}请最小化 L 并输出其最小可能值。

输入描述:
\hspace{15pt}第一行输入两个整数 N,M\left(2\leqq M\leqq N\leqq 10^{5}\right)
\hspace{15pt}第二行输入 N 个整数 A_1\dots A_N\left(1\leqq A_i\leqq 10^{5}\right)


输出描述:
\hspace{15pt}输出一个整数,表示最小化后的 L 值。
示例1

输入

4 2
1 5 2 4

输出

3

说明

选择 \{1,2\} 得到 L=2^2-1^2=3,为最小值。
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
//双指针就尽量往O(n)方向想,不然双循环必超时。
//好像排序之后,选任意两个点找最小的就可以了吧,因为递增序列任意两个之间肯定是最小的啊,在利用双指针找两个数就行了吧,不对因为是要找M个数,所以还是是要找一个子数组到达M个,
//注意优化的点,b增加后,a指针移动后,只需要减去剔除的元素差,加上新进来的元素差就可以了,这样时间复杂度就是On了,避免重复计算

int compare(const void*p1,const void *p2)
{
    return *(int*)p1-*(int*)p2;
}
int main() {
    int N,M;
    scanf("%d %d",&N,&M);
    int array[N];
    for(int i=0;i<N;i++)
    {
        scanf("%d",&array[i]);
    }

    //排序一下
    qsort(array, N, sizeof(int), compare);
    long long min_L;   //记录最小L,结果可能会很大,所以必须用longlong
    int a=0,b=0+M-1; //设定一个窗口
    //先统计第一个窗口的值
    long long temp_L=0;
    for (int i=a;i<=b-1&&b<=N-1; i++) {
        temp_L += (long long)array[i+1] * array[i+1] - (long long)array[i] * array[i];
    }
    min_L=temp_L;
    //统计剩余窗口
    a++;
    b++;
    while (b<=N-1) {
       // long temp_L=0;
            //对哦,我怎么就没想到呢,只需要减去剔除的元素差,加上新进来的元素差就可以了,这样时间复杂度就是On了,避免重复计算

        temp_L -= (long long)array[a] * array[a] - (long long)array[a-1] * array[a-1];
        temp_L += (long long)array[b] * array[b] - (long long)array[b-1] * array[b-1];
        
        if (temp_L<min_L) {
            min_L=temp_L;//统计最小
        }
        a++;//滑动到下一个窗口
        b++;
    }
    
    printf("%lld",min_L);
    return 0;
}

发表于 2025-10-19 19:16:29 回复(1)