题解 P6485 [COCI2010-2011#4] PROSJEK
洛谷。
题意
选出若干个在 $1\sim 5$ 的整数,使其平均数为 $P$。
$P$ 是一个 $1\sim 9$ 位的小数。
问选出的数最小的方案数。
分析
我们可以发现 $P=\frac{sum}{cnt}$,$sum$ 为和,$cnt$ 是选出的数的个数。
我们就有了两个方式,第一种是使其平均数不断接近 $P$,这也就有了被卡精度的问题。
第二种,我们凑出最小的 $cnt$,再用 $cnt$ 个数凑出 $sum$。
要使 $cnt$ 最小,那么我们的 $sum$ 显然也是最小。
我们的 $sum$ 明显是一个整数,我们先使我们的 $P$ 乘上 $10^{9}$,再使其下降,这也就避免了被卡精度。
此时,我们的 $cnt$ 也就是 $10^{9}$,为了使其最小,我们将 $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$,以及每个数被选的个数。
我们思考一下为什么。
令 $f_i$ 表示凑成 $i$ 的选择的最小数字的量,而这个 $f$ 应该是单调不降的,否则,这个下降的下标为 $j$($j\ge i$),倘若在选择 $f_j$ 是选择了一个不为 $1$ 的,我们就可以将其分成 $x-1$ 与 $1$。然而全选 $1$ 在 $i>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$。
从小开始也可行,但是因为我们上面是从大选起,能选就选,因此,只有 $a_5$ 是可能大于 $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;
}
}

浙公网安备 33010602011771号