题意:
给定一个序列a,定义a[1]=a[2]=1,a[n]=a[n-a[n-1]]+a[n-1-a[n-2]](n>=3),求该序列的前n项和是多少,结果对 1e9+7 取模
n<=1e18
思路:OEIS没通项,打表找规律
除第一个1之外
1 3 5 7出现了1次
2 6 10 14出现了2次
4 12 20 28出现了3次
8 24 40 56出现了4次
先算出最多出现次数,然后对于出现次数相同的数用等差数列求和
余下的暴力计算
队友lyy写的
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 typedef long long ll; 7 const int mod=1000000007; 8 int cas,i,j; 9 ll n,inv,ans[100]; 10 ll quickmi(ll x,ll y){ 11 ll ans=1; 12 while (y){ 13 if (y&1)ans=ans*x%mod; 14 x=x*x%mod; 15 y>>=1; 16 } 17 return ans; 18 } 19 ll calc(ll n){ 20 if (!n)return 0; 21 ll mi=log(n+1)/log(2); 22 ll tmp=(1ll<<(mi-1))%mod; 23 n-=(1ll<<mi)-1; 24 return (n%mod*tmp%mod+calc(n)+ans[mi])%mod; 25 } 26 int main(){ 27 inv=quickmi(4,mod-2); 28 ans[1]=1; 29 for (i=2;i<=64;i++){ 30 ll tmp=1ll<<(i-1); 31 ll Tmp=tmp%mod; 32 Tmp=Tmp*Tmp%mod*inv%mod; 33 for (j=1;j<=i;j++){ 34 ans[i]=(ans[i]+(1ll<<(j-1))%mod*j%mod*Tmp%mod)%mod; 35 if (j!=i-1)Tmp=Tmp*inv%mod; 36 } 37 } 38 scanf("%d",&cas); 39 while (cas--){ 40 scanf("%lld",&n); 41 printf("%lld ",calc(n-1)+1); 42 } 43 }