codeforces #311 C 557C. Arthur and Table(枚举+贪心)

本文介绍了一道关于桌子腿优化的问题,通过枚举方法寻找最小成本使得任意一条腿成为最长且数量超过其他腿的总数。文章详细阐述了算法设计思路与实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:

点击打开链接

题目大意:

给出一个桌子,有n个腿,每个腿的长度是l,拆掉这条腿的花费是d,当最长的腿占腿总数大于其他腿的总数,那么合法,问如何才能花费最小到达合法情况

题目分析:

突然一看,像是dp,因为是求最优解,但是没有思路,那么我就只能想到枚举最后的最长的那条腿的方法,比这条腿长的腿一定是要拆掉的,所以可以预处理出比长度为i的腿拆掉的总数和总花费,然后在枚举每个i的时候就可以o(1)的获取到大于i的总数和总花费,然后在从比当前腿小的中选花费最小的,首先对所有的腿排序,然后按从小到大枚举的过程中,利用一个数组记录下每个d值下的个数(预处理),然后每次将比它小的添加,这个操作均摊O(n)的复杂度,然后每次需要枚举200值范围内从小到大,直到当前剩余的腿的个数小于最大的腿的个数,总的复杂度是201*O(n),妥妥的能过

代码如下:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#define MAX 100007

using namespace std;

int d[MAX];
int l[MAX];
int num[207];
int mark[MAX];
int sum[MAX];
int total[MAX];

int n;

struct Node
{
    int d;
    int l;
    bool operator < ( const Node & a  ) const
    {
        return l < a.l;
    }
}b[MAX];

int main ( )
{
    while ( ~scanf ( "%d" , &n ) )
    {
        memset ( num , 0 , sizeof ( num ) );
        memset ( sum , 0 , sizeof ( sum ) );
        memset ( total , 0 , sizeof ( total ) );
        memset ( mark , 0 , sizeof ( mark ) );
        int low = MAX , up = 0;
        for ( int i = 0 ; i < n ; i++ )
        {
            scanf ( "%d" , &l[i] );
            low = min ( low , l[i] );
            up = max ( up , l[i] );
        }
        for ( int i = 0 ; i < n ; i++ )
            scanf ( "%d" , &d[i] );
        for ( int i = 0 ; i < n ; i++ )
        {
            mark[l[i]]++;
            total[l[i]] += d[i];
        }
        for ( int i = up ; i >= low ; i-- )
        {
            sum[i] = sum[i+1] + mark[i];
            total[i] += total[i+1];
        }
        for ( int i = 0 ; i < n ; i++ )
        {
            b[i].d = d[i];
            b[i].l = l[i];
        }
        sort ( b , b+n );
        int cnt = 0;
        int ans = 1e9;
        int temp;
        //cout <<"low-up : " << low << " " << up << endl;
        for ( int i =  low ; i <= up ; i++ )
        {
            if ( !mark[i] ) continue;
            while ( cnt < n && b[cnt].l < i )
                num[b[cnt++].d]++;
            temp = total[i+1];
            int p = n - sum[i];
            //cout << " test : " << i << " " << p << " " << temp << " ";
            for ( int j = 1 ; j <= 200 ; j++ )
            {
                if ( p < mark[i] ) break;
                if ( p-mark[i]+1 < num[j] )
                {
                    temp += (p-mark[i]+1)*j;
                    p -= mark[i]-1;
                    break;
                }
                temp += num[j]*j;
                p -= num[j];
            }
            //cout << temp << endl;
            ans = min ( ans , temp );
        }
        printf ( "%d\n" , ans );   
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值