链接:
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)
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
扫描二维码关注公众号,回复:
2292211 查看本文章
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;
}
}
过了。。中间的过程就不说了,一点一点优化,让我有了新的目标