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

题目链接:

点击打开链接

题目大意:

给出一个桌子,有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 );   
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
协同过滤算法(Collaborative Filtering)是一种经典的推荐算法,其基本原理是“协同大家的反馈、评价和意见,一起对海量的信息进行过滤,从中筛选出用户可能感兴趣的信息”。它主要依赖于用户和物品之间的行为关系进行推荐。 协同过滤算法主要分为两类: 基于物品的协同过滤算法:给用户推荐与他之前喜欢的物品相似的物品。 基于用户的协同过滤算法:给用户推荐与他兴趣相似的用户喜欢的物品。 协同过滤算法的优点包括: 无需事先对商品或用户进行分类或标注,适用于各种类型的数据。 算法简单易懂,容易实现和部署。 推荐结果准确性较高,能够为用户提供个性化的推荐服务。 然而,协同过滤算法也存在一些缺点: 对数据量和数据质量要求较高,需要大量的历史数据和较高的数据质量。 容易受到“冷启动”问题的影响,即对新用户或新商品的推荐效果较差。 存在“同质化”问题,即推荐结果容易出现重复或相似的情况。 协同过滤算法在多个场景中有广泛的应用,如电商推荐系统、社交网络推荐和视频推荐系统等。在这些场景中,协同过滤算法可以根据用户的历史行为数据,推荐与用户兴趣相似的商品、用户或内容,从而提高用户的购买转化率、活跃度和社交体验。 未来,协同过滤算法的发展方向可能是结合其他推荐算法形成混合推荐系统,以充分发挥各算法的优势。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值