HDU 6304 Chiaki Sequence Revisited(玄学找规律)
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1270 Accepted Submission(s): 324
题意
已知递推公式a[n]=a[i-a[i-1]]+a[i-1-a[i-2]],求数列a的前n项和。
解题思路
比赛的时候查了半天的OEIS,一点用都没有,打了好久的表,也没找到什么实质性的规律。后来看大佬直播讲题的时候,弹幕中有人说这题是用lowbit找规律。第二天就发现有个大佬写了这个思路的博客,地址是https://blog.csdn.net/wyj_alone_smile/article/details/81177111,照着大佬的思路写了代码。规律是具有相同lowbit的数出现的次数均为log(lowbit(x))+1。惊了!!大佬是怎么找到的orz。然后我根据出现的次数,草草的打了个表,如下图
由于篇幅有限,右边还有老长一段没截下来。不过由此图就很容易就能发现出现一次的就是首项为1公差为2的等差数列,出现两次的是首项为2公差为4的等差数列……这样问题就变成了求几个等差数列的和。由于大佬的博客思路很清楚,我自己写了遍感觉跟他的差不多,还是放出来吧,以后自己也看得见。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100;
const int mod = 1e9+7;
long long p[maxn],num[maxn],n;
long long inv=(mod+1)/2;//2的逆元,不用逆元目测会炸
int lowbit(int x){return x&(-x);}
int getamo(long long x){return lower_bound(p,p+63,x)-p+1;} //获得出现的次数
long long solve(long long x)
{
long long ans=0;
for(long long i=1;i<=x;i*=2)
{
long long amo=(x-i)/(i*2);//数列元素的个数-1
long long maxx=i+amo*i*2; //maxx为尾项,i为首项
amo=(amo+1)%mod;
maxx=((i+maxx)%mod*amo)%mod*inv%mod;//等差数列求和
maxx=maxx*getamo(i)%mod;
ans=(ans+maxx)%mod;
}
return (ans+1)%mod;
}
int main()
{
p[0]=num[0]=1;
for(int i=1; i<=63; i++) p[i]=p[i-1]*2,num[i]=2*num[i-1]+1;
int t;
while(~scanf("%d",&t))
{
while(t--)
{
scanf("%lld",&n);n--;
if(n==0) {
printf("1\n");
continue;
}
long long tmp=n,sum=0;
for(int i=62;i>=0;i--)
if(tmp>=num[i]) tmp-=num[i],sum+=p[i];
long long ans=solve(sum);
if(tmp){
ans=(ans+tmp*(sum+1))%mod;
}
printf("%lld\n",ans);
}
}
return 0;
}
/*1010110011011000110110011011000011011001101100011011001101100000110110011011000110110011011000011011001...*/