zoukankan      html  css  js  c++  java
  • #82. 【UR #7】水题生成器

    链接: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=12020204040 都是 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≤55!=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;
    } 
    代码
  • 相关阅读:
    让windows cmd也用上linux命令
    数据库工具toad与plsql
    Oracle表&DATA复制
    主流WEB开发语言简单对比
    游戏中的碰撞检测
    LRU算法总结及其C算法实现
    MTU
    多款as3游戏框架
    请问2.3e+71,是不是表示23后面有70个0?
    希望OFFICE有一个小阳台,在阳光斜照的下午,开发人员能喝着茶,在蓝色的天空下讨论问题,这样思绪更为清楚
  • 原文地址:https://www.cnblogs.com/CLGYPYJ/p/7394662.html
Copyright © 2011-2022 走看看