HDU 6304 Chiaki Sequence Revisited 二分+规律

/**
G: Chiaki Sequence Revisited
链接:http://acm.hdu.edu.cn/showproblem.php?pid=6304
题意:求解所给序列的前缀和;

分析:先拍出40个a[i]的表 得到:
1 1 2 2 3 4 4 4 5 6 6 7 8 8 8 8 9 10 10 11 12 12 12 13 14 14 15 16 16 16 16 16 17 18 18 19 20 20 20 21
对于任意两个相邻且不等的数字,差值均为1
对于每个数字第一次出现的位置打上标记,可以发现是一个2^k的循环
对于每一个数字n,首先可以找到小于等于它的最大的2^k -1个数字
而2^k-1个数字其对应的a的值只增加了2^(k-1)个数字
最后你就会发现:

1 3 5 7 9 .......     出现1次的差为2的等差数列

2 6 10 14 18.....   出现2次的差为4的等差数列

4 12 20 28 36 .....  出现3次的差为8的等差数列

8 24 40 56 72 ....  出现4次的差为16的等差数列
因此只需要知道等差数列的长度  就可以获得前缀和了;

然而接下来 窝并不知道二分 难道是签到题吗???好烦啊.....
为什么我观察不出来呢....................... 挂比我的好吧

好了 那就直接说吧 二分 二分找出a[n] 为了求出前n项和 你会发现次数为i的数的首相为2^(i-1),公差为2^i。
那么通过这个规律 只需要枚举出现的次数 然后计算前缀和即可得到答案;


*/

#include<bits/stdc++.h>
#define ll long long 
using namespace std;

const double eps=1e-6;
const int maxn=1e3+7;
const int mod=1e9+7;
ll a[maxn],f[maxn];


int main(){
    ll T;
    scanf("%lld",&T);
    a[0]=f[0]=1;
    for(int i=1;i<=62;i++) a[i]=a[i-1]*2+1,f[i]=f[i-1]*2;
    ll inv=(mod+1)/2;
    while(T--){
        ll pos=0,n,m,ma=-1,ans=0;
        scanf("%lld",&n);
        m=n;
        for(ll i=62;i>=0;i--) if(m-a[i]>=0) m-=a[i],pos=pos+(1ll<<i);
        pos+=(m>0);
        ll now=pos-1,num=0;
        for(ll i=1;f[i-1]<=now;i++){
            ll s=f[i-1],step=(now-s)/f[i]+1,e=(step-1)*f[i]+s;
            ll haha=(s+e)%mod*(step%mod)%mod*inv%mod;
            ans=(ans+haha*i%mod)%mod;
            num+=step*i;
        }
        ans=(ans+1+(n-num-1)%mod*(pos%mod)%mod)%mod;
        printf("%lld\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/hypHuangYanPing/article/details/81783237
今日推荐