代码改变世界

暑假集训(1)第一弹 -----士兵队列训练问题(Hdu1276)

2016-07-16 15:56  HUAS_周林微  阅读(322)  评论(0编辑  收藏  举报

Description

某部队进行新兵队列训练,将新兵从一开始按顺序依次编号,并排成一行横队,训练的规则如下:从头开始一至二报数,凡报到二的出列,剩下的向小序号方向靠拢,再从头开始进行一至三报数,凡报到三的出列,剩下的向小序号方向靠拢,继续从头开始进行一至二报数。。。,以后从头开始轮流进行一至二报数、一至三报数直到剩下的人数不超过三人为止。
 

Input

本题有多个测试数据组,第一行为组数N,接着为N行新兵人数,新兵人数不超过5000。
 

Output

共有N行,分别对应输入的新兵人数,每行输出剩下的新兵最初的编号,编号之间有一个空格。
 

Sample Input

2 20 40
 

Sample Output

1 7 19 1 19 37
 
问题分析
显然最初士兵之间的间隔为1、1......,但是在报二后,只留下奇数位,从而导致他们的间隔会翻倍变为2、2.....,
1  2  3  4  5  6  7.....
1      3      5     7......
而在报三后每三个数失去一位,则间隔变为2、4......
1  3  5  7  9  11  13.......
1  3      7  9       13.......
 
由此假设报二的次数为n次,报三的次数为n次(n!=0)
得士兵排序为1   1+2*3E(n-1)   1+2*3En;  
 
注意:N<=3 和 排列序号大于士兵人数N的情况 以及报二报三次数不一致的情况。
 
 1 #include "iostream"
 2 
 3 using namespace std;
 4 
 5 int main()
 6 {
 7     int t,N;
 8     int i,j,k;
 9     cin>>t;
10     while (t--)
11     {
12       i=1;
13       j=1;
14       cin>>N;
15       k=N;
16       if (N<=3)
17       {
18         for (int i=1;i<=N;i++)
19           {
20            cout<<i;
21            if (i!=N)
22              cout<<' ';
23            else
24              cout<<endl;
25           }
26            continue;
27       }
28       while (1)
29       {
30           N = N-N/2;
31           i = i+j; j = i;
32           if (N <= 3)
33                  break;
34           N = N-N/3;
35            j = i+j;
36            if (N <= 3)
37                  break;
38       }
39       cout<<1<<' '<<i+1;
40       if (i+j+1<=k)
41        cout<<' '<<i+j+1;
42        cout<<endl;
43     }
44      return 0;
45 }
View Code