CODEFORCES 525E Anya and Cubes

题意

有 n 个数字,先在里面选择若个,然后可以再在其中把最多 k 个数字变成其的阶乘,最后求这些数字的和。问你有多少种方法可以使和变成 S。

(1n25,0kn,1S1016,1ai109)

链接:http://codeforces.com/problemset/problem/525/E

思路

这个题如果 S 比较小的话,自然有 dp 思路:f(i,j,s) 表示使用前 i 个数字,并把选出的数字中的 j 个变成它的阶乘,最后组合成 s 的方案数目。

我们考查递推: f(i+1,j,s) f(i+1,j,s+ai+1) f(i+1,j+1,s+(ai+1)!) 分别加上 f(i,j,s)

问题就是 S 太大。这样是行不通的,不过我们发现第三维有大多数状态都是达不到的:因为数字太少,方案没有那么多。所以启发我们使用 std::map 的键代替第三维,枚举 s 变成枚举 std::map 中的键。

然,如果强行递推,不假思量的话是不会有好结果的。因为即使数字很少,最坏的状况下也有 325=8472886094438×1011 种不同的和。不管是空间还是时间都不允许你硬刚。

然,如果上述的和的数目开个根号的话那就没什么问题了。所以我们使用折半的技巧。处理出前面一半的数字再使用若干个阶乘的情况下产生某些和的方案数。同理处理后一半。枚举前面和后面合适的使用阶乘的数目,再枚举前面可以产生的和 X ,最后在另一半中查找是否有组成 SX 的方案。如果有的话,根据计数乘法原理,结果要加上产生 X 的方案数和产生 SX 的方案数的乘积。于是大功可成。

代码:https://code.csdn.net/snippets/1583964/master/cf525E.cpp/raw

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值