Byedance AI Camp-笔试题目

最小m段和问题给定n个整数组成的序列,现在要求将序列分割为m段,每段子序列中的数在原序列中连续排列。如何分割才能使这m段子序列的和的最大值达到最小?

Input

第一行输入一个整数t,代表有t组测试数据。
每组数据第一行为两个整数n,m分别代表序列的长度和最多可分的段数。
接下来一行包含n个整数表示序列。
0<=n<=50000 1<=m<=n,0<=ai<=2^30。

Output

输出一个整数表示和最大的一段的最小值。

#if 0 //内存爆,30%

#include<iostream>  
#include<algorithm>  
#include<cstring>  
#include<cstdio>  
using namespace std;

typedef long long ll;
ll a[100001], f[10001][10001];

int main()
{
    int n, m, i, j, k;
    ll maxt, tmp;
    while(scanf("%d%d",&n,&m)==2)  
    {  
        memset(f,0,sizeof(f));  
        for(i=1;i<=n;i++)  
        {  
            scanf("%d",&a[i]);  
            f[i][1] = f[i - 1][1] + a[i];
        }

        for (i = 2; i <= m; i++)
        {
            for (j = i; j <= n; j++)
            {
                tmp = 2147483647L ; //tmp = LONG_MAX; 
                for (k = i; k<j; k++)
                {
                    maxt = max(f[k][i - 1], f[j][1] - f[k][1]);
                    if (tmp>maxt)
                        tmp = maxt;
                }
                f[j][i] = tmp;
            }
        }
        printf("%d\n", f[n][m]);
    }
    return 0;
}
#endif



#if 0 //AC


#include <cstdio>  
#include <algorithm>  
using namespace std;

#define MAX(a,b) a>b?a:b   

typedef long long ll;

int n, m;
ll a[100001];
ll sum;
ll maxx;

bool judge(ll x)
{
    ll duan = 0;//表示分的段数   
    ll he = 0;
    for (int i = 0; i<n; i++)
    {
        if (he + a[i]>x)//当当前段再加一段长度后超过了x的值,那么新开一段   
        {
            duan++;
            he = a[i];
            if (duan >= m)//当还没有扫完这个序列但是已有的段数已经超过了所规定的段数   
            {
                return false;
            }
        }
        else
        {
            he = he + a[i];//延长该段   
        }
    }
    return true;
}

int main()
{
    while (scanf("%d%d", &n, &m) == 2)
    {
        sum = 0;
        maxx = -1;
        for (int i = 0; i < n; i++)
        {
            scanf("%lld", &a[i]);
            sum = sum + a[i];
            maxx = MAX(maxx, a[i]);
        }
        ll l = maxx, r = sum;//左区间用maxx是因为所分的段里面如果不含该序列的最大值,那么这个段子的和一定大于最大值,右区间为sum是因为不分的时候段子和为sum   
        ll mid, ans;
        while (l <= r)
        {
            mid = (l + r) / 2;
            if (judge(mid))//看是否能将序列分成符合段数不大于m 且最大和接近mid的段子们   
            {
                ans = mid;
                r = mid - 1;//求的最小值   
            }
            else
            {
                l = mid + 1;
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}


#endif

「问题描述」类似的题目:

给定一个n*m的矩阵,矩阵中的每个元素aij为正整数。

接下来规定

1.合法的路径初始从矩阵左上角出发,每次只能向右或向下走,终点为右下角。

2.路径经过的n+m-1个格子中的元素为A1,A2…A(n+m-1),Aavg为Ai的平均数,路径的V值为(n+m-1)*∑(Ai-Aavg) ^2

(1<=i<=n+m-1)

求V值最小的合法路径,输出V值即可,有多组测试数据。

 

猜你喜欢

转载自www.cnblogs.com/ranjiewen/p/9093029.html