OC Round #9 简单的取石子游戏

本文探讨了一种涉及取石子的游戏算法,目标是最小化操作次数使每堆石子数量成为某数的倍数。通过分解质因数和动态规划,文章详细解释了如何高效解决这一问题。

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

10165 : 简单的取石子游戏
时间限制: 1000 MS 内存限制: 131072 KB 提交总数: 28 AC总数: 11
问题描述
现在有n堆石子,且已知每堆石子的数量,每次操作你可以从任一堆中取一颗石子放到另一堆中,问最少操作几次使得每一堆石子的数量均是某一个数的倍数。
输入格式
首先,输入一个n,代表有n堆石子。
第二行有n个数,第i个数记为a[i],代表第i堆得初始石子数。
【数据范围】
1<=n<=100000,1<=a[i]<=100000。
输出格式
输出最少操作次数。
样例输入
样例输入1:
5
1 2 3 4 5
样例输入2:
2
5 7
样例输出
样例输出1:
2
样例输出2:
1

#include<algorithm>
#include<cstdio>
#include<cstring>
#define N 100010
using namespace std;
typedef unsigned long long ull;
int a[N],n,g[N],gp,c[N];
ull sum,ans=1<<31,cnt;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum+=a[i];
    for(ull x=2;x*x<=sum;x++)//分解质因数 
    while(sum%x==0)g[++gp]=x,sum/=x;
    if(sum>1)g[++gp]=sum;//手误,写成sum>0
    for(int i=1,w;i<=gp;i++)
    {
        sum=w=cnt=0;
        memset(c,0,sizeof c);
        for(int j=1,t;j<=n;j++)
        {
            t=a[j]%g[i];
            if(t>0)c[++w]=t,sum+=t;//需要花费步数来达到状态 
        }
        sort(c+1,c+w+1);
        for(int j=w;j;j--)//倒序,这样移动的步数会少 
        {
            cnt+=g[i]-c[j];
            sum-=g[i];//至多w堆石子加上这堆刚好都是b[i]的倍数 
            if(sum<=0)break;
        }
        ans=min(ans,cnt);
    }
    printf("%lld",ans);
    return 0;
} 
  • 列表内容
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oj_onecode

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值