首页 > 试题广场 >

计数器

[编程题]计数器
  • 热度指数:3776 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解

小爱有一个奇怪的计数器。在第一个时刻计数器显示数字3,在接下来的每一个时刻,屏幕上的数字都会减1,直到减到1为止。

接下来,计数器会重置为上一个计数周期初始值的两倍,然后再每一个时刻减1。具体过程如下图所示:

找出规律,并打印出t时刻计数器的值。

输入描述:
输入为时刻t,一个整形数字。0<t<1e12


输出描述:
计数器显示的值。
示例1

输入

4

输出

6
#include <iostream>
using namespace std;
int main(void){
    //1e12大于int类型范围
    long long t, time = 3;
    cin>>t;
    while(t > time){
        t -= time;
        time *= 2;
    }
    cout<<time+1-t<<endl;
    return 0;
}
变量time表示当前周期的起始计数大小,分别是3,6,12,...,t减去相应的周期大小,当t不大于下一周期大小时,表示在当前周期显示,观察题目所给的表格,发现time+value为定值,为了表示方便,再把time减去上一周期的起始值,得到索引1,2,3,...这些索引值加上value之和等于本周期起始计数值加1
编辑于 2019-08-23 15:59:38 回复(1)
//非迭代版本
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        long time = scanner.nextLong();
        long value = 3;
        while(time - value > 0){
            time -= (value);
            value <<= 1;
        }
        value -= time - 1;
        System.out.println(value);
    }
}


编辑于 2019-07-08 19:12:12 回复(0)

可以看到每一组time和value相加的和是一样的,4、10、22、48...,且这些之间的差依次为6、12、24...规律就出来了。

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        long t = Long.parseLong(br.readLine());
        long sum = 4L, n = 6L;
        while (t >= sum) {
            sum += n;
            n *= 2;
        }
        System.out.println(sum - t);
    }
}
编辑于 2019-07-31 16:46:17 回复(0)
t=input('');
x=3; a=3;
while 1
    if t<3
        fprintf('%d',4-t);
        break
    elseif t-a<2*x
        fprintf('%d',2*x-(t-a)+1);
        break
    else
        x=x*2; a=a+x;
    end
end

编辑于 2020-06-03 18:08:06 回复(0)
#include <bits/stdc++.h>
using namespace std;
int main(){
    long t,v=3,k=1;
    cin>>t;
    while(t>=k){
        k += v;
        v<<=1;
    }
    cout<<k-t<<endl;
    return 0;
}

发表于 2019-11-02 08:53:37 回复(0)
#include <bits/stdc++.h>
using namespace std;
int main(){
    int t,velue=3,index=1;
    cin>>t;
    while(index<=t){
        index+=velue;
        velue<<=1;
    }
    cout<<index-t;
    return 0;
}


发表于 2019-10-19 16:49:15 回复(0)
#######################################################计数器
import math
s = int(input())
#先计算s属于第几个计数器
n = math.ceil(math.log(s/3+1,2))   #要向上取整
#再计算是第几个数
print(3*(2**(n-1)) - s+ 3*(2**(n-1))-2)
发表于 2019-09-13 12:55:21 回复(0)
#include<bits/stdc++.h>
using namespace std;
int main()
{
    long long t,n=3,m=1,f=3;
    cin>>t;
    while(m<t)
    {
        m=m+f;
        f=2*f;
    }
    if(m==t)
        cout<<f<<endl;
    else
    {
        f=f/2;
        m=m-f;
        long long res=f-(t-m);
        cout<<res<<endl;
    }
    return 0;
}

发表于 2019-08-21 20:53:35 回复(0)
没观察太多,第一个数是3依次递减,减到0的时候value=value*2就ok啊
发表于 2019-07-29 21:05:20 回复(0)
int main() {   
    long t = 0;  
    cin >> t;     long start =  1;  
    while (start<=t)    
  {        
     start = (start *2 +2);   
  }    
  printf("%ld", start - t);     return 0;
}
主要是找规律吧,每一列开始time值分别1,4(=2*1+2),10=(2*4+2),22=(2*10+2),。。。
找到每一列开头time值,就好办了。
通过循环,找到元素t所在列的下一列开头元素time值为start,注意到其中每一列的value值是从下往上递增,然后start-t 即为t对应是value值。

编辑于 2019-07-27 22:56:17 回复(0)
这个题就是找数学公式,也就是等比数列n项和的公式,然后反推!主要用的就是math相关的
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc= new Scanner(System.in);
long m=sc.nextLong();
double n= Math.ceil(Math.log(m/3.0+1)/Math.log(2));
System.out.println((long)(3*Math.pow(2, n-1)-m+3*(Math.pow(2, n-1)-1)+1));//里面可以合并
}
}


然后发现后面的输出里面可以合并
于是:
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc= new Scanner(System.in);
long m=sc.nextLong();
double n= Math.ceil(Math.log(m/3.0+1)/Math.log(2));
System.out.println((long)(6*Math.pow(2, n-1)-m-2));
}
}
这个算法时间复杂度是O(1),比其他的O(lgn)的要好一些!
编辑于 2019-07-25 10:04:23 回复(0)
#include <iostream>

int main()
{
    long int t,tTemp=1;
    int n=1;
    std::cin >> t;
    while ((t-(((tTemp <<n)-1)*3))>0)
    {
        n++;
    }
    t = t - ((tTemp <<( n-1)) - 1) * 3;
    std::cout << (3*(tTemp <<(n-1)))-t+1<< std::endl;
}
发表于 2019-07-10 10:58:21 回复(0)
#include<stdio.h>
#include<math.h>
int main()
{
    long long time;
    long long value;
    long long time_init;
    long long low;//hangshu 0kaishi
    scanf("%ld",&time);
    low=(int)(log((time+2)/3)/log(2));
    time_init=3*pow(2,low)-2;
    value=time_init+2-(time-time_init);
    printf("%ld",value);
    
    return 0;
}
找出规律 开头的time是3*2^i-2   value是3*2^i   其中i是行数从0开始的。用输入的时间求出行数,再求输入的时间与这行开头的时间差(time-time_init),再用开头的value减去
发表于 2021-08-19 15:12:24 回复(0)
t=int(input())
tik=0
base=3
while t>base:
    t=t-base
    tik+=1
    base=2*base
res=base-t+1
print(res)

发表于 2021-03-27 11:01:51 回复(0)
#include<iostream>
#include<cmath>
int main()
{
    long long t;
    while(std::cin>>t)
    {
        long double d=(t+3.0)/3.0;
        long long a=log2(d);
        if(pow(2,a)==d)std::cout<<1<<std::endl;
        else
        {
            long long b=t-3*(pow(2,a)-1);
            long long c=3*pow(2,a)-b+1;
            std::cout<<c<<std::endl;
        }

    }
    return 0;
}
发表于 2020-09-18 18:20:27 回复(0)
#include <iostream>
using namespace std;
int main()
{
    unsigned long long a,b,t,r;//足够用的数据类型
    cin>>t;
    a=3,b=3;
    while(t>a)//计算到t出现的周期
    {
        a+=2*b;//左下元素time的规律
        b*=2;//右上元素value规律
    }
    r=a-t+1;//t时刻的计数值
    cout<<r<<endl;
    return 0;
}

编辑于 2020-08-15 20:42:09 回复(0)
import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()){
            long n = Long.parseLong(sc.nextLine());
            long i = 0;
            long cur = 0;
            long nextcur = 0;
            while(true){
                cur = 1 * 3 * i + 1;
                nextcur = 1 * 3 * (2*i+1)+1 ;
                if(n<nextcur && n >=cur){
                    break;
                }
                i = 2*i + 1;
            }
            cur -= (n - cur -2);
            System.out.println(cur);
        }
    }
}
不太聪明的解法
发表于 2020-06-30 13:05:19 回复(0)
#include<iostream>
#include<algorithm>
using namespace std;

int main()
{
    long long t;
    cin>>t;
    long long n=0;
    n=(long long)(log((t+3)/3)/log(2)-1);
    long long m=3*(pow(2,n+2)-1);
    cout<<m+1-t<<endl;
    return 0;
}
发表于 2020-06-22 15:29:36 回复(0)
t = int(input())

# 判断属于哪一组
n = 1
while(t > (3*pow(2,n) - 3)):
    n = n + 1

s = 3*pow(2,n) - 2
print(s - t)




编辑于 2020-06-15 15:11:09 回复(0)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

int main()
{
    unsigned int i = 0;
    unsigned long t = 0, data = 0, f = 0, data_old = 0;
    while(EOF != scanf("%ld", &t))
    {
        do {
            data += 3*pow(2,i);
            if(t<=data) {
                break;
            }
            i++;
        }while(1);
        
        f = data + 1 - t;
        printf("%ld\n",(f));
    }
    return 0;
}

开始scanf(%d)和printf(%d)导致参数越界,%d为有符号十进制整形,改为%ld后成功。
发表于 2020-05-25 20:39:01 回复(0)