把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

题解 P6485 [COCI2010-2011#4] PROSJEK

洛谷

题意

选出若干个在 15 的整数,使其平均数为 P

P 是一个 19 位的小数。

问选出的数最小的方案数。

分析

我们可以发现 P=sumcntsum 为和,cnt 是选出的数的个数。

我们就有了两个方式,第一种是使其平均数不断接近 P,这也就有了被卡精度的问题。

第二种,我们凑出最小的 cnt,再用 cnt 个数凑出 sum

要使 cnt 最小,那么我们的 sum 显然也是最小。

我们的 sum 明显是一个整数,我们先使我们的 P 乘上 109,再使其下降,这也就避免了被卡精度。

此时,我们的 cnt 也就是 109,为了使其最小,我们将 cnt 与此时的 sum 除上其最小公倍数。

int cnt=1000000000;
P*=cnt;
int T=P,gcd=__gcd((int)P,cnt);
T/=gcd,cnt/=gcd;

此时,我们找到了我们的最小 cnt,接下来就来到了解决,用 cnt 个数凑出 sum

我们可以用背包解决,但是 sum 可能会很大,限制了此想法。由此,我们分析一下,我们最容易解决的方案是什么。

我们可以找到在当前 sum 下的最小的凑成的数量,令其为 tot

怎么做呢,我们从最大选起,能选就选,就能得到我们的 tot,以及每个数被选的个数。

我们思考一下为什么。

fi 表示凑成 i 的选择的最小数字的量,而这个 f 应该是单调不降的,否则,这个下降的下标为 jji),倘若在选择 fj 是选择了一个不为 1 的,我们就可以将其分成 x11。然而全选 1i>1 时明显并不是最优的。

int tot=0;
for(int i=5;i;--i) {
a[i]=T/i;
T=T-i*a[i];
tot+=a[i];
}

这时,我们的 tot 显然是小于等于我们的 cnt
我们需要使数量增加。

显然,我们需要使一些数分裂成更多的数。

为了使我们的分解更加便于操作,我们可以从最大开始,不断分出 1,这样我们就可以不断使 tot+1

从小开始也可行,但是因为我们上面是从大选起,能选就选,因此,只有 a5 是可能大于 1 的,因此从 5 开始会对我们的 tot 有更大的影响,更加快捷。(但是只有 5 个好像都无所谓?)

在正确性上,只要我们存在方案,那么我们必然可以凑出,因为我们是一步一步加的。

while(tot<cnt) {
int id=0;
for(int i=2;i<=5;++i) if(a[i]) id=i;
int dt=cnt-tot;
if(a[id]>=dt) {
a[id]-=dt;
a[1]+=dt;
a[id-1]+=dt;
tot+=dt;
}else {
a[1]+=a[id];
a[id-1]+=a[id];
tot+=a[id];
a[id]=0;
}
}
posted @   djh0314  阅读(17)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
浏览器标题切换
浏览器标题切换end
点击右上角即可分享
微信分享提示