• hdu2062 Subset sequence----递推


    题目链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=2062

    题目大意:

    给出n和m,集合{1,2,,,,n}的非空子集,按照一定方式排列,例如n==3时,

    1
    1    2
    1    2    3
    1    3
    1    3    2
    2
    2    1
    2    1    3
    2    3
    2    3    1
    3
    3    1
    3    1    2
    3    2
    3    2    1
    然后输出第m个序列。
     
    思路:
    先小规模枚举,n = 1时有1个序列,n=2时有4个序列,n=3时有15个序列。
    可推出F[n] = n * (F[n - 1] + 1),F[n]表示n个元素的序列个数。那就可以想到,给定一个m,可以先推出第1位,比如n = 3,m = 6时,第一位肯定是2,那我们可以递推下去,确定第一位,然后m减小,再递推出下一位。
    还是之前的例子,n = 3, m = 6, 1开头的有5个,2开头的有5个,这样可以用7除以5向上取整,求出目前是第几位,所以得出以下解法:
     
    首先设c = (m + F[n - 1] ) / (F[n - 1] + 1)(这是m除以F[n - 1] + 1 向上取整),c就表示当前这一位是第c小的。
    然后m = m - (c - 1) * (F[n - 1] + 1),n--,这样就可以循环下去,求目前的n和m中的第一位是什么,这里要注意的是m还得自减一,还是用上面的例子说明,求出第一位为2后,m = 1, n = 2;我们知道m = 1, n = 2按照上面的公式算出来c = 1,也就是在1,3之中第一小的数字,就是1,序列是2,1,这与答案有误,答案应该就是2,错误的原因在于这个序列的构造,n = 2时只有4种,而我们的m算出来最大可以为5(就是n=3,m = 10的时候,循环之后n = 2, m = 5),所以m应该自减一,这样正好可以对应上,如果自减一之后等于0,就应该退出循环,结束构造,这样就可以得到之前的正确答案“2”。在每次求出一位之后,数组应该左移一位,这样可以直接利用移动后的数组来求当前第c小的数字
     
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<string>
     6 using namespace std;
     7 typedef long long ll;
     8 int cases;
     9 const int maxn = 1e5 + 100;
    10 typedef long long ll;
    11 ll n, m, a[30];
    12 void init()
    13 {
    14     a[1] = 1;
    15     for(ll i = 2; i < 21; i++)a[i] = i * (a[i - 1] + 1);
    16     //for(int i = 1; i <= 20; i++)cout<<a[i]<<endl;
    17 }
    18 int main()
    19 {
    20     init();
    21     while(cin >> n >> m)
    22     {
    23         int b[30], ans[30], tot = 0;
    24         for(int i = 1; i <= n; i++)b[i] = i;
    25         while(m > 0)
    26         {
    27             int c = (m + a[n - 1]) / (a[n - 1] + 1);
    28             //cout<<m << " "<<c<<" "<< n<<endl;
    29             ans[tot++] = b[c];
    30             n--;
    31             for(int i = c; i <= n; i++)b[i] = b[i + 1];
    32             m -= (c - 1) * (a[n] + 1);
    33             m--;
    34             if(m <= 0)break;
    35 
    36         }
    37         cout<<ans[0];
    38         for(int i = 1; i < tot; i++)cout<<" "<<ans[i];
    39         cout<<endl;
    40     }
    41 }
     
  • 相关阅读:
    查找整数
    Ling To Xml 学习之 对xml增、删、改、查
    JS获得鼠标
    xml之数据岛绑定到表格
    C# 三种序列化[转]
    编程字体
    Oracle 、C#
    提示信息Javascript
    几个好用的日历控件
    收藏网站
  • 原文地址:https://www.cnblogs.com/fzl194/p/8676302.html
Copyright © 2020-2023  润新知