传送门
找规律可以发现:
ans=∑i∗a[i]i=1..n
即原数列中所有不超过
n
的数的和
容易发现一个数
所以答案就是最后一个
#include <bits/stdc++.h>
using namespace std;
#define prt(k) cerr<<#k" = "<<k<<endl
typedef long long ll;
typedef long long LL;
const int N = 450100;
int a[N]; // a[i] : i出现次数
const LL mod = 1e9+7;
LL mul(LL a, LL n)
{
a %= mod, n %= mod;
LL r = 0;
for (; n>0; n>>=1, a=(a+a)%mod) if (n&1) r=(r+a)%mod;
return r;
}
ll pmod(ll a, ll n)
{
ll r = 1; for (; n>0; n>>=1, a=a*a%mod) if (n&1) r=r*a%mod;
return r;
}
int n, m;
LL dp[N];
int s[N];
int main()
{
m = 0;
a[++m] = 1;
a[++m] = 2;
a[++m] = 2;
s[1] = 1;
s[2] = 3;
LL inv2 = pmod(2, mod-2);
for (int n=3;m<N-1 && n<N;n++) {
for (int i=0;m<N-1 && i<a[n];i++) {
if (m == N-1) break;
a[++m] = n;
}
}
s[0] = 0;
for (int i=1;i<N;i++) s[i]=s[i-1]+a[i];
dp[0] = 0;
for (int i=1;i<N;i++) {
dp[i] = dp[i-1];
LL t = mul(i, s[i-1] + s[i] + 1);
t = mul(t, s[i] - s[i-1] + mod);
t = mul(t, inv2);
dp[i] = (dp[i] + t) % mod;
}
int re; cin>>re;
while (re--) {
scanf("%d", &n);
int id = upper_bound(s+1, s+N, n) - s - 1;
LL ans = dp[id];
LL t = mul(s[id] + n + 1, id + 1);
t = mul(t, n - s[id] + mod);
t = mul(t, inv2);
ans = (ans + t) % mod;
printf("%I64d\n", ans);
}
return 0;
}