首页 > 试题广场 >

牛牛与切割机

[编程题]牛牛与切割机
  • 热度指数:3154 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
有一个序列 a_1, a_2, ..., a_n , 牛牛将对这个序列切割一刀(划分分成两个不相交的非空序列,一个序列为 a_1, \dots, a_p,另一个序列为 a_{p+1}, \dots, a_n),牛牛切割的代价为两个序列元素和的乘积。牛牛想知道切割代价最小是多少。

输入描述:
第一行输入一个整数 n,表示序列的长度 2 \leq n \leq 10^6
第二行输入 n 个整数 a_1, a_2, \dots, a_n,表示序列的元素 -10^3 \leq a_i \leq 10^3


输出描述:
输出一个整数表示切割代价最小是多少。
示例1

输入

5
1 2 3 4 5

输出

14

说明

序列被划分为1 和 2 3 4 5,右边和为 14。
示例2

输入

4
2 1 3 4

输出

16

说明

序列被划分为 2 和 1 3 4。
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        long minSum = Long.MAX_VALUE;
        int i = 0;
        int[] values = new int[n];
        while(i < n) {
            values[i] = in.nextInt();
            i++;
        }

        if(n == 1) {
            System.out.println(values[0]);
            return;
        }

        long sum = Arrays.stream(values).sum();
        long sum1 = 0;
        long sum2 = sum;


        i = 0;
        while(i < n - 1) {
            
            sum1 += values[i];
            
            sum2 -= values[i];

            minSum = Math.min(minSum, sum1 * sum2);

            i++;
        }

        System.out.println(minSum);
        // 注意 hasNext 和 hasNextLine 的区别
        // while (in.hasNextInt()) { // 注意 while 处理多个 case
        //     int a = in.nextInt();
        //     int b = in.nextInt();
        //     System.out.println(a + b);
        // }
    }
}

发表于 2025-06-25 17:07:52 回复(0)
从数学上来说,cost(p)=left(p)×(totalleft(p))=left(p)(totalleft(p)) 也就是cost是一个f(x)=x(totalx)=x^2+kx的抛物线,中间只有最大值,最小值在两头,因此只需要将最左边的切一刀或者最右边切一刀,然后比较最小值即可。因此这道题没啥意义!
发表于 2025-06-18 09:41:25 回复(3)
#include <iostream>
#include<vector>
#include<climits>
#include<algorithm>
typedef long long ll;
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin>>n;

    vector<ll>prefix(n+2,0);
    ll sum = 0;
    for(int i = 1; i <= n;i++){
        int tmp;
        cin>>tmp;
        sum += tmp;
        prefix[i] = prefix[i - 1] + tmp;
    }
    ll cost = LLONG_MAX;
    for(int i = 1;i <= n - 1;i++){
        ll less = sum - prefix[i];
        cost = min(cost,less * prefix[i]);
    }
    cout<<cost<<'\n';
}
// 64 位输出请用 printf("%lld")
先预处理前缀和数组,然后根据题意可知:切割代价即prefix[i] * (sum - prefix[i]),切割代价最小即为:min(cost,(sum - prefix[i]) * prefix[i])。注意一点:由于题目要求非空序列,所以在计算cost的过程中循环条件为i <= n - 1;
发表于 2025-12-21 17:41:48 回复(0)

设做序列和为x,总序列和为常数k,则右序列和为k-x;

即问题可等价为:求y=x(k-x)=-x^2+xk的最小值,抛物线开口向下,则其最小值必在两个端点处取得。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        long[] arr = new long[n];
        long totalSum = 0; // 存储序列总元素和
        
        // 读取序列元素并计算总 sum
        for (int i = 0; i < n; i++) {
            arr[i] = in.nextInt();
            totalSum += arr[i];
        }
        
        // 计算两个端点切割的代价(核心:最小值必在这两个切割点中)
        // 切割点1:左序列仅含第1个元素,右序列含剩余n-1个元素
        long cost1 = arr[0] * (totalSum - arr[0]);
        // 切割点2:左序列含前n-1个元素,右序列仅含最后1个元素
        long cost2 = (totalSum - arr[n - 1]) * arr[n - 1];
        
        // 取两个代价的最小值作为结果
        long minCost = Math.min(cost1, cost2);
        System.out.println(minCost);
        
        in.close();
    }
}


编辑于 2025-10-15 10:08:00 回复(0)
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        int n = in.nextInt();
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = in.nextInt();
        }

        int[] preSum = new int[n + 1];
        preSum[0] = 0;
        for (int i = 1; i < preSum.length; i++) {
            preSum[i] = arr[i - 1] + preSum[i - 1];
        }
        long sum1 = 0, sum2 = 0;
        long sum = Long.MAX_VALUE;
        for (int i = 0; i < n-1; i++) {
            sum1 = preSum[i + 1] - preSum[0];
            sum2 = preSum[n] - preSum[i + 1];
            sum = Math.min(sum, sum1 * sum2);

        }
        System.out.print(sum);
    }
}


发表于 2025-09-08 11:11:00 回复(0)
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void async function () {
    let n,list
    while(line = await readline()){
        if(n){
            list = line.split(' ').map(item=>parseInt(item))
        }else{
            n = parseInt(line)
        }
    }
    let minn = Infinity,right=list.reduce((pre,curr)=>pre+curr,0),left=0
    for(let i=0;i<list.length-1;i++){
        left+=list[i]
        right-=list[i]
        minn = Math.min(minn,left*right)
    }
    console.log(minn)
}()
发表于 2025-12-09 14:41:58 回复(0)
import math
n = int(input())
li = list(map(int,input().split()))

min_cost = math.inf
sum_li = sum(li)

# 获取前缀和
li_new = [li[0]]
for j in range(1,n):
    li_new.append(li_new[j-1]+li[j])

for i in range(1,n):
    left_sum_li = li_new[i-1]
    right_sum_li = sum_li-left_sum_li
    curr_cost = left_sum_li*right_sum_li
    min_cost = min(min_cost,curr_cost)
print(min_cost)

发表于 2025-10-06 17:38:20 回复(0)
#include <bits/stdc++.h>
using namespace std;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n;
    cin >> n;
    vector<long long> prefix;
    long long x;
    prefix.push_back(0);
    for(int i=1;i<=n;i++){
        cin>>x;
        prefix.push_back(prefix.back()+x);
    }
    long long min=LLONG_MAX,sum;
    for(int i=1;i<n;i++){
        sum=prefix[i]*(prefix[n]-prefix[i]);
        if(sum<min)
        min=sum;
    }
    cout<<min;
}

发表于 2025-09-24 10:46:28 回复(0)
def min_cut_cost(sequence):
    n = len(sequence)
    if n < 2:
        return 0  # 序列长度至少为2才能切割
    
    # 计算序列的总 sum
    total_sum = sum(sequence)
    
    # 计算前缀和并寻找最小代价
    prefix_sum = 0
    min_cost = float('inf')
    
    # 尝试所有可能的切割点(从1到n-1)
    for i in range(n - 1):
        prefix_sum += sequence[i]
        suffix_sum = total_sum - prefix_sum
        cost = prefix_sum * suffix_sum
        
        if cost < min_cost:
            min_cost = cost
    
    return min_cost



发表于 2025-07-31 20:38:02 回复(0)
#include <iostream> #include <vector> #include <algorithm> int main() { int n; std::cin >> n; std::vector<int> a(n); for (int i = 0; i < n; ++i) { std::cin >> a[i]; } long long total_sum = 0; for (int i = 0; i < n; ++i) { total_sum += a[i]; } long long cost1 = a[0] * (total_sum - a[0]); long long cost2 = (total_sum - a[n-1]) * a[n-1]; long long min_product = std::min(cost1, cost2); std::cout << min_product << std::endl; return 0; }</int></algorithm></vector></iostream>
发表于 2025-06-18 10:50:10 回复(1)