zoukankan      html  css  js  c++  java
  • 【t030】数字构造

    Time Limit: 3 second
    Memory Limit: 256 MB

    【问题描述】

    有这么一个游戏: 写出一个1~N的排列a[i],然后每次将相邻两个数相加,构成新的序列,再对新序列进行这样的操作,显然每次构成的序列都比上一次的序列长度少1,直到只剩下一个数字位置。下面是一个例子:
    3 1 2 4
    4 3 6
    7 9
    16
    最后得到16这样一个数字。
    现在想要倒着玩这样一个游戏,如果知道N,知道最后得到的数字的大小sum,请你求出最初序列a[i],为1~N的一个排列。若答案有多种可能,则输出字典序最小的那一个。
    【数据规模】
    对于40%的数据,n≤7;
    对于80%的数据,n≤10;
    对于100%的数据,n≤12,sum≤12345,且保证一定有解。
    【输入格式】

    输入文件bds.in的第1行为两个正整数n,sum。
    

    【输出格式】

    输出文件bds.out包括1行,对于每个询问输出答案。
    

    【输入样例1】

    4 16
    【输出样例1】

    3 1 2 4

    【题目链接】:http://noi.qz5z.com/viewtask.asp?id=t030

    【题解】

    可以画一画样例
    这里写图片描述
    注意观察一下最后的答案;
    发现其实最后答案=3*1+3*2+1*3+1*4
    可以看到第一行的各项的系数是分别是C[3][0],C[3][1],C[3][2],C[3][3];
    发现规律!
    最后的答案就为
    设第一行的第i列元素为a[i]
    则最后一行的那一个元素为∑a[i]*C[n-1][i-1]
    则我们先预处理出组合数(C[i][j] = C[i-1][j-1]+C[i-1][j])
    然后枚举第一行的各个元素分别是什么;
    然后O(1)得到最后一行的那唯一一个元素;
    看看是不是所要求的sum;
    因为这个∑符号里面的各项都是正数,所以可以写一个剪枝;
    如果前i项的∑a[i]*C[n-1][i]>sum,则直接剪掉;就不用再等到i=n的时候再判断了;
    sum比较小;这个剪枝还是很强力的;

    【完整代码】

    #include <cstdio>
    #include <cstdlib>
    #define rei(x) scanf("%d",&x)
    #define rep1(i,x,y) for (int i = x;i <= y;i++)
    const int MAXN = 15;
    
    int n,sum,a[MAXN];
    int c[MAXN][MAXN];
    bool bo[MAXN];
    
    void dfs(int x,int now)
    {
        if (now > sum)
            return;
        if (x>n)
        {
            if (now==sum)
            {
                rep1(i,1,n)
                {
                    printf("%d",a[i]);
                    if (i==n)
                        puts("");
                    else
                        putchar(' ');
                }
                exit(0);
            }
            return;
        }
        rep1(i,1,n)
        if (!bo[i])
            {
                bo[i] = true;
                a[x] = i;
                dfs(x+1,now+c[n-1][x-1]*a[x]);
                bo[i] = false;
            }
    }
    
    int main()
    {
        rep1(i,1,13)
            c[i][i] = c[i][0] = 1;
        rep1(i,1,13)
            rep1(j,1,i-1)
                c[i][j] = c[i-1][j-1]+c[i-1][j];
        rei(n);rei(sum);
        if (n==1)
            puts("1");
        else
            dfs(1,0);
        return 0;
    }
  • 相关阅读:
    一台电脑上的git同时使用两个github账户
    git自己操作命令组集合
    git基本原理
    js如何遍历表单所有控件
    js如何访问表单(四种方法)(博客园+li的方式去掉p标签)
    js如何操作表格(常用属性方法汇总)
    php数学和时间常用函数有哪些(总结表)(看学习视频效率挺高的)(复习)
    swift 笔记 (十九) —— 协议
    ecshop广告调用方法
    K60 启动过程分析
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626689.html
Copyright © 2011-2022 走看看