HDU-6304 Chiaki Sequence Revisited(找规律)

题目:求数列的前n项和。

每个数出现的次数是log(lowbit(i))+1次,可以二分出a[n]的值,对于同样的次数会构成了一个等差数列。公差就是2^i,项数是n/2^i.

太菜了自己打表没弄出来,参考了https://blog.csdn.net/purple_bro/article/details/81177315写的好详细。

#include
using namespace std;
void dabiao()
{
    int a[100],sum[100];
    vectornum[100];

    a[1]=a[2]=1;
    sum[1]=1;sum[2]=2;
    for(int i=3;i<100;i++)
    {
        a[i]=a[i-a[i-1]]+a[i-1-a[i-2]];
        sum[i]=sum[i-1]+a[i];
        printf("%2d:%4d%6d\n",i,a[i],sum[i]);
    }
    for(int i=1;i<100;i++)
    {
        int tmp=1,k=a[i];
        while(a[i]%2==0)
        {
            a[i]/=2;
            tmp++;
        }
        num[tmp].push_back(k);
    }
    for(int i=1;i<=8;i++)
    {
        for(int j=0;j>=1;
    }
    return ans;
}
bool check(ll x)//除以每个2^i就可以得出2^i有多少个,这样子加完就得到对应的a[x]是多少。
{
    ll num=0;
    for(int i=0;i<=63;i++)
        num+=x/p[i];
    return num>=n-1;
}
ll solve(ll x)
{
    ll num=0;
    for(int i=0;i<=63;i++)
        num+=x/p[i];
    return num;
}
int t;
int main()
{
    dabiao();
    ll inv2=qmod(2ll,mod-2);
    p[0]=1;
    for(int i=1;i<=63;i++)
        p[i]=p[i-1]*2;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld",&n);
        ll l=max(n/2-30,1ll),r=min(n,n/2+30),pos;
        while(l<=r)//二分找n对应的a[n],pos记录下a[n]
        {
            ll mid=(l+r)>>1;
            if(check(mid))
            {
                pos=mid;
                r=mid-1;
            }
            else l=mid+1;
        }
        ll s=pos-1,ans=1;//pos-1是因为在a[n]位置的n可能不是刚好符合2^i,所以要找前面一个,前面一个必定是符合2^i个的
        for(int i=0;i<=63;i++)
        if(s>=p[i])
        {
            ll a1=1,an=s/p[i]%mod;
            (ans+=p[i]*(a1+an)%mod*an%mod*inv2%mod)%=mod;//等差数列求和
        }
        (ans+=(n-1-solve(s))%mod*pos%mod)%=mod;///处理最后多出来的那些不参与上面等差数列的项
        printf("%lld\n",ans);
    }
    return 0;
}

 

你可能感兴趣的:(数学,多校)