链接:http://uoj.ac/problem/82
今天是世界水日,著名的水题资源专家蝈蝈大臣向世界宣布了他的一项新发明 —— 水题生成器。 每道题目都有一个正整数的难度值。水题生成器虽然强大但是功能有限。水题生成器内部有一个参数 nn,你可以告诉水题生成器一个能整除 n!n! 的正整数 dd,水题生成器就会产生一道难度值恰为 dd 的水题。这里 n!n! 表示 nn 的阶乘。 现在蝈蝈大臣的助手欧姆想用水题生成器产生不超过 nn 道水题,且难度值之和恰为 mm。保证 1≤m≤n!1≤m≤n!。 欧姆当然知道怎么做啦!但是他想考考你。请你给出一组合法方案或输出无解。 输入格式 第一行一个正整数 nn。 第二行一个正整数 mm。保证 1≤m≤n!1≤m≤n!。 输出格式 不超过 nn 行,每行一个正整数 dd,表示你每次告诉水题生成器的难度值。 输出的每个难度值都必须是 n!n! 的约数,且难度值之和恰为 mm。 如果有多组解,输出任意一组均可。如果无解请直接输出卖萌表情 “>w<”(不含引号) 样例一 input 5 100 output 40 40 20 explanation 5!=1×2×3×4×5=1205!=1×2×3×4×5=120。2020 和 4040 都是 120120 的约数,且 40+40+20=10040+40+20=100。 样例二 input 10 3628800 output 3628800 限制与约定 测试点编号 nn的规模 1, 2, 3, 4, 5, 6 n≤5n≤5 7, 8, 9, 10, 11, 12, 13, 14 n≤9n≤9 15, 16, 17, 18, 19, 20 n≤20n≤20 时间限制:1s1s 空间限制:256MB
其实我也不会看了题解。。。
还是直接看题接的解释吧:
题解
水题生成器 from taorunz 算法一 对于前6个数据n≤5n≤5,5!=1205!=120,只有1616个约数。 我们直接用165165枚举这些子集,找到一个和等于mm的集合即可。 当然,由于nn很小,你还可以用分类讨论之类的方法乱搞。 期望得分:30分 算法二 对于前14个数据n≤9n≤9. 我们可以将本问题看成一个背包问题来解。 时间复杂度是O(d(n!)∗m)O(d(n!)∗m)的, 其中d(x)d(x)表示xx的约数。 期望得分:70分 算法三 本题与阶乘紧密相关,说到把不超过n!n!的数分解成nn个数的和,最容易想到的就是阶乘进位制。(就是分解成 ∑kak⋅k!∑kak⋅k! 且 ak≤kak≤k) 然而在本题里,用阶乘进位制分解得到的数不一定是n!n!的约数。 (例如样例一,阶乘进位制分解为100=96+4=4×4!+2×2!100=96+4=4×4!+2×2!,96却不是120约数) 怎么办呢? 把阶乘进位制倒过来! 我们令新的进位制的第kk位的位值为 n(n−1)⋯(n−k)n(n−1)⋯(n−k) 然后将mm分解,我们发现分解出来的数都是形如n(n−1)⋯(n−k)akn(n−1)⋯(n−k)ak的数。而akak是小于(n−k)(n−k)的! 这样n(n−1)⋯(n−k)akn(n−1)⋯(n−k)ak就一定是n!n!的约数,本题圆满解决啦! 期望得分:100分 算法四 不知道阶乘进位制?没关系!我们可以直接贪心! 我们先算出n!n!的所有约数(n=20n=20时有4104041040个),然后从大到小依次尝试减去当前数,直到减为零为止。 有趣的是,用这种方法,一定可以在不超过nn步内减到零! 为什么呢?我们参考算法三,对于当前剩余要造题的难度值之和m′m′ ,我们可以将它表示成反阶乘进位制后,取出最高位的数。这样就可以使得m′m′降低一个(反阶乘进位制的)数量级。而算法四所取出来的数不会比算法三取出的低,所以算法四也可以保证每次使得m′m′降低一个(反阶乘进位制的)数量级。而总共数量级最多为nn,一定能够在nn次内减到零。 期望得分:100分
#include<cstdlib> #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> using namespace std; #define LL unsigned long long LL n,tot=1,m; int main() { cin>>n>>m; for(int i=1;i<=n;i++) tot*=i; for(int i=1;i<=n;i++) { tot/=i; if(tot<=m) { printf("%lld ",tot*(m/tot)); m-=tot*(m/tot); } } return 0; }