里面求最大区间和的第二种方法之所以<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;
}