Day 1 G - Chiaki Sequence Revisited HDU 6304 | 打表找规律

前缀和

里面求最大区间和的第二种方法之所以<0便将sum清零,是因为求的是最大和而非区间。所以只要更新最大和就可以。下面的ans = max(ans, sum),如果因为出现负数而开始减少那么这个和是不会被算进去的,一旦ans小于0就清空的意思是重新开始计数(找一个新的区间)。

树状数组

差分序列

写完之后WA了好几发,检查出几个问题:
1 %mod不要只在更新ans的时候进行,可能加减法的时候也会溢,能mod的时候就%mod
2 但是也不是所有运算都可以mod,比如i这里表示首项,如果超过1e9但并没有过1e18,mod之后就不是正确的首项了。
3 inv2学到新知识惹,(a/b)mod n = a * b ^ (n-2)!!而不能直接%mod
4 最后发现一直WA是getvalue内部声明p的时候使用了int p 而不是ll p,导致溢出。以后测试的时候要多注意这些细节。
5 对拍按教程捣鼓了一会没弄出来,今晚垃圾时间可以再研究研究 后来学会对拍了

题解

#include <bits/stdc++.h>

using namespace std;

#define endl '\n'
#define ll long long

int T;
const ll mod = 1e9+7;
const int inv2 = 500000004;

ll getfi(ll i)//求出最后一个值为i的数字在数列中的位置(次数前缀和)
{
    //if(i%2 == 1) return 1;
    if(i <= 1) return i;
    return getfi(i/2)+i;
}

ll getvalue(ll n)//求出第n项的值是多少
{
    ll upb = n/2+30, lowb = n/2-30, tes, ans=-1;
    while(lowb <= upb)
    {
        tes = (upb + lowb) / 2;

        //
        ll temp = getfi(tes);
        //cout << "getfi(tes) = " << temp << "  n = " << n << endl;

        if(getfi(tes) > n)
            upb = tes-1;
        else
        {
            lowb = tes + 1;
            ans = tes;
        }
    }

    //第n项值为ans
    //cout << "ans = " << ans << endl;
    return ans;
}

void solve(ll n)
{
    ll p = getvalue(n);//第n项值为p

    //cout << "p = " << p ;

    //依次求各个A.P.和
    ll c = 1, sx, mx, xs, gc, apsum, ans = 0;
    for(ll i = 1; ;i *= 2, c++)
    {
        if(i > p) break;
        sx = i%mod;
        gc = 2*i%mod;
        xs = ((p - i) / (i*2) + 1)%mod;
        mx = (gc * (xs - 1)%mod + i)%mod;
        //mx %= mod;
        apsum = ((c*(sx + mx)%mod * xs%mod)*inv2 %mod)%mod;
        apsum %= mod;
        ans += apsum;

        //cout << "xs= " << xs << " mx = " << mx << " sx = " << sx << endl;
        //cout << "i = " << i << " apsum = " << apsum << "  ans = " << ans << endl;
        ans %= mod;
    }
    //
    ans += ((n - getfi(p))*((p+1)%mod))%mod;

    //cout << "res = " << n - getfi(p) << endl;
    //cout << "an = " << p+1 << endl;
    //cout << "ans = " << ans << endl;


    ans %= mod;
    ans ++;

    printf("%lld\n", ans);
}

int main()
{
    scanf("%d", &T);
    while(T)
    {
        ll n;
        scanf("%lld", &n);
        n--;
        solve(n);

        T--;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值