【HDOJ】1276 士兵队列训练问题

本文深入解析了一个类似于尤瑟夫问题的数学挑战,但起始数字为1。通过递归公式和逆向思维,作者详细介绍了如何找到最终剩余数字的初始值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

初看这道题目很像尤瑟夫问题, 区别是每次都是从1开始。解法也很类似。数学解递推公式。
假定第K次报数后,余下人数不超过3个人。
若第K次为1-3报数,那么由这三个数的当前索引n可推上一次报数之前的编号为n+(n-1)/2,该式也很容易理解,因为每三个人就要去掉第三个人,因此(n-1)/2可以知道已经减少了几个人,加上基础编号n就是上一次报数的编号;
若第K次为1-2报数,这个很简单,当前索引为n的数在上一次报数时编号为2n-1。
因此,县求解报数的次数,然后逆向求得余下的数字的初始值。

 1 #include <cstdio>
 2 #include <cstring>
 3 
 4 int main() {
 5     int t, n, m;
 6     int i, j;
 7     int a[4];
 8 
 9     scanf("%d", &t);
10     while (t--) {
11         scanf("%d", &n);
12         m = 0;
13         while (n > 3) {
14             ++m;
15             if (m & 1)
16                 n -= n/2;
17             else
18                 n -= n/3;
19         }
20         for (i=1; i<=n; ++i)
21             a[i] = i;
22         while (m > 0) {
23             if (m & 1) {
24                 for (i=1; i<=n; ++i)
25                     a[i] = 2*a[i]-1;
26             } else {
27                 for (i=1; i<=n; ++i)
28                     a[i] = a[i]+(a[i]-1)/2;
29             }
30             --m;
31         }
32         printf("%d", a[1]);
33         for (i=2; i<=n; ++i)
34             printf(" %d", a[i]);
35         printf("\n");
36     }
37 
38     return 0;
39 }

 

转载于:https://www.cnblogs.com/bombe1013/p/4062966.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值