对于一个由 0..n 的所有数按升序组成的序列,我们要进行一些筛选,每次我们丢弃去当前所有数字中第奇数位个的数。重复这一过程直到最后剩下一个数。请求出最后剩下的数字。
数据范围:
,本题有多组输入
以 n = 37 为例,即 0 ~ 37
time = 1,开始位置 base = 0,每次位置新增为 up=2,删除的值为:time = 2,开始位置 base = 1,每次位置新增为 up = 4,删除的值为:time = 3,开始位置 base = 3,每次位置新增 up = 8,删除的值为:
import java.util.Scanner;
/**
* @author GJXAIOU
*/
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int inputValue = scanner.nextInt();
if (inputValue == 0) {
System.out.println(0);
}
int[] values = new int[inputValue + 1];
for (int i = 0; i < values.length; i++) {
values[i] = i;
}
// time 表示第几次运行删除
int time = 1;
// 每次删除的第一个数
int base = 0;
// 每次删除时候递增的间隔
int up = 2;
// 还有多少值没有检查替换
int left = values.length;
while (left > 1) {
for (int i = base; i < values.length; i += up) {
values[i] = 0;
left--;
}
base = (int) (base + Math.pow(2, time - 1));
// 进行下一次
time++;
// 每次运行删除间隔都是 2 的倍数
up *= 2;
}
for (int i = 0; i < values.length; i++) {
if (values[i] != 0) {
System.out.println(values[i]);
}
}
}
}
}
#include<iostream>
#include<vector>
#include<math.h>
using namespace std;
int main(){
int n;
while(cin>>n){
int times=1,begin=0;
while(n!=1){
begin=begin+pow(2,(times-1));
n/=2;
times++;
}
cout<<begin<<endl;
}
return 0;
}
/*每次只需记录第一个记录,由于数字之间的间隔每分一次增大一倍,可以由公式begin=begin+pow(2,(times-1)); 计算出下一个第一位数的值*/
import java.util.Scanner;
// 找规律每次删除后的第一个数为2^times - 1然后算出 times 即可
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int n = scanner.nextInt();
int total = n + 1;
int times = 0;
while (total != 1) {
total /= 2;
times++;
}
System.out.println(String.format("%.0f", Math.pow(2, times) - 1));
}
}
}
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
int n=sc.nextInt();
ArrayList<Integer> array=new ArrayList<Integer>();
for(int i=0;i<n;i++)
array.add(i);
int i=0;
while(array.size()>1){
array.remove(i);
i++;
if(i>=array.size())
i=0;
}
System.out.println(array.get(0));
}
}
} import java.util.Scanner;
public class DiscardOdd {
/**
* 思路: 序列是从 0 到 n-1 的 n 个数, 但是序列的索引是从 1 开始的;<br>
* 假如 n = 10, 那么序列的索引为: 1, 2, 3, ...10;<br>
* 第一次被淘汰掉的索引为: 1, 3, 5,7, 9; 这些索引满足的条件为: index%2 != 0;<br>
* 剩下来的序列索引为: 2, 4, 6, 8, 10; 在这些索引中满足奇数条件: index%4 != 0 的索引为: 2, 6, 10;<br>
* 所以这些索引对应的值将会被在第二轮被淘汰掉;<br>
* 剩下类的索引为: 4, 8;其中满足奇数条件: index%8 !=0 的索引为: 8; 所以最后剩下来的索引就是 8;<br>
* 而索引 8 对应的值为 7, 所以最后剩下来的值为 7.<br>
*
* 由以上推理可以得知, 最后剩下来的那个索引满足条件: index%2^n != 0, 其中 2^n 为小于 n 里面的最大一个.<br>
* 由于索引是从 1 开始的, 而序列的值是从 0 开始的, 所以最后的结果应该为 index - 1;<br>
*
*/
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int n = scanner.nextInt();
int base = (int) Math.floor(Math.log(n) / Math.log(2));
System.out.println((1 << base) - 1);
}
scanner.close();
}
}
package NiuKeBianMa;
//有些像那个约瑟夫环的题目
//重复置零的操作
import java.util.Scanner;
public class Main84 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int n = scanner.nextInt();
int i = 1;
int count = 1;
while (Math.pow(2, i + 1) < n) {
count += Math.pow(2, i);
i = i + 1;
}
System.out.println(count);
}
}
}
#include <iostream>
#include <list>
using namespace std;
int main()
{
int n;
while (cin >> n)
{
list<int> nums;
for (int i = 0; i <= n; ++i) nums.emplace_back(i);
while (nums.size() > 1)
{
int count = 0;
for (auto p = nums.begin(); p != nums.end();)
{
++count;
if (count & 1) p = nums.erase(p);
else ++p;
}
}
cout << *nums.begin() << endl;
}
return 0;
} import java.util.Scanner;
public class Main{
static class Node{
int index;
Node next;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while(in.hasNext()){
int n = in.nextInt();
Node root = new Node();
root.index = 0;
Node temp = root;
for(int i = 1;i<=n;i++){
Node node = new Node();
node.index = i;
temp.next = node;
temp = node;
}
temp = root.next;//删除第一个
root = temp;
while(root.next!=null){
if(temp==null||temp.next==null){
temp = root.next;//删除第一个
root = temp;
}else{
Node nextTemp = temp.next.next;
temp.next = nextTemp;
temp = nextTemp;
}
}
System.out.println(root.index);
}
}
}
#include <cstdio> int main() { int n; while(scanf("%d", &n) != EOF){ int b = 1; while(b <= n + 1){ b <<= 1; } printf("%d\n", (b >> 1) - 1); } return 0; }
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
int n = sc.nextInt();
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i <= n; i ++ )
list.add(i);
while (list.size() != 1) {
// 从0开始list移除一次,i再加一次,i始终指向奇数位
for (int i = 0; i < list.size(); i = i + 1)
list.remove(i);
}
System.out.println(list.get(0));
}
}
}
//常规做法,比较直观,用数组a每次循环清楚记录了每次删除后剩余的元素。
#include<iostream>
using namespace std;
int main(){
int n,i,a[1001],count;
while( cin >> n ){
for(i=0;i<=n;i++)
a[i] = i;
count = n+1;
while( count != 1 ){
for(i=0;2*i+1<count;i++)
a[i] = a[2*i+1];
count = i;
}
cout << a[0] << endl;
}
}
//特殊思路,每次删除所在数组位置的二进制最右端为0的元素。如0(0)2(10)4(100)
//剩余的元素1(01)3(11)5(101)下一次其位置变成了之前位置左移一次后的
// 1(1) 3(10) 5(10) 然后继续按之前规则删除最右端为0的元素。故原始序列中,谁的//二进制下从右往左数,1最多,则最后删除,因每次删除移位后,最右端仍然为1,会保留
#include<iostream>
using namespace std;
int main(){
int n;
while( cin >> n ){
int b = 1;
while( b <= n )
/*b = (b<<1) + 1;//或者 用*/ b = b*2 +1;
cout << (b>>1) << endl;
}
}