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 }

 

 
posted @ 2018-03-30 15:07  _努力努力再努力x  阅读(201)  评论(0编辑  收藏  举报