小q的数列(规律+减少时间)

链接: https://www.nowcoder.com/acm/contest/122/H
来源:牛客网

题目描述

小q最近迷上了各种好玩的数列,这天,他发现了一个有趣的数列,其递推公式如下:

f[0]=0 f[1]=1;
f[i]=f[i/2]+f[i%2];(i>=2)

现在,他想考考你,问:给你一个n,代表数列的第n项,你能不能马上说出f[n]的值是多少,以及f[n]所代表的值第一次出现在数列的哪一项中?(这里的意思是:可以发现这个数列里某几项的值是可能相等的,则存在这样一个关系f[n'] = f[n] = f[x/2]+f[x%2] = f[x]...(n'<n<x) 他们的值都相等,这里需要你输出最小的那个n'的值)(n<10^18)

输入描述:

输入第一行一个t
随后t行,每行一个数n,代表你需要求数列的第n项,和相应的n'
(t<4*10^5)

输出描述:

输出每行两个正整数
f[n]和n',以空格分隔
示例1

输入

2
0
1

输出

0 0
1 1

题意很清晰,但是数据范围太大,因此肯定有规律。

先把他们都列出来,二进制比较一下,发现二进制的位数就是该值,例:

f0=0

f1=1

f2=2=1

f3=2+1=2

f4=4=1;

f5=4+1=2

f6=4+2=2

f7=4+2+1=3

f8=8=1

f9=8+1=2

f10=8+2=2

f11=8+2+1=3

f12=8+4=2

f13=8+4+1=3

f14=8+4+2=3

f15=8+4+2+1=4

f16=16=1

f17=16+1=2

f18=16+2=2

f19=16+2+1=3

f20=16+4=2

f21=16+4+1=3

......

这个规律很好找,但是直接写出来容易超时,一开始我用的快速幂,直接超时

#include<stdio.h> 
#include<string.h> 
#include<math.h> 
   
//#include<map>  
//#include<set>
#include<deque> 
#include<queue> 
#include<stack> 
#include<string> 
#include<iostream> 
#include<algorithm> 
using namespace std; 
   
#define ll long long 
#define da    0x3f3f3f3f 
#define clean(a,b) memset(a,b,sizeof(a))// 水印
 
 
 
ll quick(ll result)
{
    ll n=1;
    while(result>=n)
        n=n<<1;
    return n/2;
}
 
ll quick_take(ll n)
{
    ll product=1;
    ll can=2;
    while(n)
    {
        if(n&1)
            product=product*can;
        can=can*can;
        n=n>>1;
    }
    return product;
}
 
int main()
{
    ll t;
    cin>>t;
    while(t--)
    {
        ll n;
        cin>>n;
        ll sum=0;
        while(n)
        {
            n=n-quick(n);
            sum++;//多少个不同的分解
        }
        ll num=0;
        for(ll i=0;i<sum;++i)
            num=num+quick_take(i);//最小的哪一个的位置
        cout<<sum<<" "<<num<<endl;
    }
}

发现超时,大概估算了一下,64*2*64*4*4*10^5....很明显是千万次的循环。。优化:

#include<stdio.h>  
#include<string.h>  
#include<math.h>  
  
//#include<map>   
//#include<set>
#include<deque>  
#include<queue>  
#include<stack>  
#include<string>  
#include<iostream>  
#include<algorithm>  
using namespace std;  
  
#define ll long long  
#define da    0x3f3f3f3f  
#define clean(a,b) memset(a,b,sizeof(a))// 水印 

int main()
{
	ll t;
	cin>>t;
	while(t--)
	{
		ll n;
		cin>>n;
		ll sum=0;
		while(n)//每一位都找一下
		{
			if(n&1)
				sum++;
			n=n>>1;
		}
		ll num=0;
		for(ll i=0;i<sum;++i)//最小的哪一个
			num=num*2+1;
		cout<<sum<<" "<<num<<endl;
	}
}
过了。。中间的过程就不说了,一点一点优化,让我有了新的目标



猜你喜欢

转载自blog.csdn.net/qq_40482358/article/details/80382433