2019-2020 ICPC, NERC, Northern Eurasia Finals J. Just Arrange the Icons(贪心+数学)

本文解析了一种算法,旨在解决如何使用最少数量的箱子装下所有物品的问题,每个箱子只装同一类型的物品且尽量装满。通过枚举可能的箱子大小并检查其合法性,最终确定最优解。

题目链接
大意:给你一个序列,表示所有物品的种类,让你用最少的箱子装下所有物品,大小任意但需满足:
箱子中必须只能装一种数,且必须装满活着差一个装满。 物品的大小都为1。
思路:显然,我们要枚举一些大小来获得答案,那么我们用一个集合和储存合法答案,然后check所有的答案来获得一个符合所有物品的箱子大小。
初始的集合显然要从出现最少的种类获得。
主要的地方就是check是否合法了。

//p[1] 表示出现最少次数的种类数
if(p[1]%i==0)res[0][++len[0]]=i;//如果是倍数的话,显然可以
else{//否则,我们判断是否可以通过减少塞满的箱子 来 获得一个 合法的箱子
    int l=p[1]/i;
    int r=p[1]%i;
    if(l+r>=i-1)res[0][++len[0]]=i;
}

剩下就是不断更新合法集合即可。
细节见代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e6 + 10;
#define fi first
#define se second
#define pb push_back
int t,n,a[N],cnt[N],p[N],x,res[2][N],y,len[2];
int main() {
    for(scanf("%d",&t);t;t--){
        scanf("%d",&n);x=0;
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),cnt[a[i]]++;
        for(int i=1;i<=n;i++){
            if(!cnt[i])continue;
            p[++x]=cnt[i];
        }
        sort(p+1,p+1+x);len[0]=0;
        for(int i=p[1]+1;i>=1;i--){
            if(p[1]%i==0)res[0][++len[0]]=i;
            else{
                int l=p[1]/i;
                int r=p[1]%i;
                if(l+r>=i-1)res[0][++len[0]]=i;
            }
        }
        int sta=0;
        for(int i=2;i<=x;i++){
            len[sta^1]=0;
            for(int j=1;j<=len[sta];j++){
                if(p[i]%res[sta][j]==0){
                    len[sta^1]++;
                    res[sta^1][len[sta^1]]=res[sta][j];
                }else{
                    int l=p[i]/res[sta][j];
                    int r=p[i]%res[sta][j];
                    if(l+r>=res[sta][j]-1){
                        len[sta^1]++;
                        res[sta^1][len[sta^1]]=res[sta][j];
                    }
                }
            }
            sta^=1;
        }
        int an=n,num;
        for(int j=1;j<=len[sta];j++){
            int re=0;num=res[sta][j];
            for(int i=1;i<=x;i++){
                re+=p[i]/num+(p[i]%num?1:0);
            }
            an=min(an,re);
        }
        printf("%d\n",an);
        for(int i=1;i<=n;i++)cnt[a[i]]--;
    }
    return 0;
}
### 计算从1到N的阶乘之和 在编程竞赛中,计算从1到N的阶乘之和是一个常见的题目。以下是实现该功能的方法以及一些注意事项。 #### 方法描述 可以通过循环来逐步累加每个数的阶乘值。由于阶乘增长非常迅速,因此需要注意数据类型的选取以防止溢出。通常情况下,在C++中可以选择`unsigned long long`作为存储结果的数据类型[^3]。 下面提供了一个基于C++的标准解决方案: ```cpp #include <iostream> using namespace std; int main() { unsigned int n; cout << "Enter a positive integer: "; cin >> n; unsigned long long sum = 0; // 存储最终的结果 unsigned long long factorial = 1; // 当前的阶乘值 for (unsigned int i = 1; i <= n; ++i) { factorial *= i; // 更新当前阶乘值 sum += factorial; // 累加至总和 } cout << "Sum of factorials from 1 to " << n << " is: " << sum << endl; return 0; } ``` 此代码片段展示了如何通过简单的迭代方法完成任务。注意这里使用了`unsigned long long`以适应较大的数值范围。 对于Python而言,其内置的大整数支持使得处理此类问题更加简便: ```python def factorial_sum(n): total, fact = 0, 1 for i in range(1, n + 1): fact *= i # Update the current factorial value. total += fact # Add it to the running total. return total n = int(input("Enter a number: ")) print(f"The sum of factorials up to {n} is:", factorial_sum(n)) ``` 上述Python版本无需担心数据类型的选择问题,因为Python自动管理大整数运算[^1]。 #### 性能优化建议 当面对更大的输入规模时,应考虑算法的时间复杂度与空间复杂度。尽管本题目的直接解法已经足够高效,但在更复杂的场景下可能还需要引入动态规划或其他高级技巧[^2]。 另外,利用标准模板库(STL),如向量(vector)或者列表(list),可以帮助更好地管理和操作大量中间结果。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值