杭电多校第一场 1007 Chiaki Sequence Revisited

杭电多校第一场 1007 Chiaki Sequence Revisited

1007 Chiaki Sequence Revisited

题意


给定 a n 的递推式,求 a n 的前缀和

打表

1 1
2 2
3
4 4 4
5
6 6
7

8 8 8 8
9
10 10
11 12 12 12
13
14 14
15
16 16 16 16 16

我们设数字i出现的次数 为 f ( n )
观察到规律,每一个数出现的次数是该数里含2的因子数的个数+1,转化成数学语言就是
如果有 n = 2 i t ( 2 t
那么有 f ( n ) = i + 1
唯一例外的就是1,排除掉这个就行了
那么从 1,…n 出现次数总和是多少呢
设为g(n)
g ( n ) = <munderover> i = 1 n </munderover> f ( i ) = n + n / 2 + n / 4 + n / 8 + . . . . . // 注意是整除
这个概念和阶乘尾零的求法很相似
例如 n = 8 的时候

n/ i 个数
n = 8 1 2 3 4 5 6 7 8 8个数字算一次
n/2 = 4 2 4 6 8 4个数字算二次
n/4 = 2 4 8 2个数字算三次
n/8 = 1 8 1个数字算四次
出现次数 1 2 1 3 1 2 1 4 15

好了我们知道这个规律之后就可以求得 a n 的值了,方法就是二分枚举 a n 的值,如果有 a n = m i d 则必有 g ( m i d 1 ) < n <= g ( m i d )

如果知道 a n 的值之后怎么求前缀和呢

求前缀和

<munderover> i = 1 i = n </munderover> a i = <munderover> i = 1 i = g ( m i d 1 ) </munderover> a i + <munderover> i = g ( m i d 1 ) + 1 n </munderover> a i = <munderover> i = 1 i = g ( m i d 1 ) </munderover> a i + ( n g ( m i d 1 ) ) m i d
所以问题转化成了 如何求 <munderover> i = 1 i = g ( m i d 1 ) </munderover> a i
我们又知道 每个数出现的次数

所以 <munderover> i = 1 i = g ( m i d 1 ) </munderover> a i = <munderover> i = 0 </munderover> m i d 1 2 i ( m i d 1 2 i + 1 ) 2 i
举例说明
1 2 3 4 5 6 7 8 求和一次 1 ( 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 ) = 1 8 ( 8 + 1 ) 2
2 4 6 8 求和一次是 2 ( 1 + 2 + 3 + 4 ) = 2 4 ( 4 + 1 ) 2
4 8 求和是 4 ( 1 + 2 = 4 2 ( 2 + 1 ) 2 ;

代码如下


#include <bits/stdc++.h>
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define me(ar) memset(ar,0,sizeof(ar))
#define lowbit(x) (x&(-x))
#define Pb push_back
#define FI first
#define SE second
#define For(i,a,b) for(int i = a; i < b; ++i)
using namespace std;
typedef  long long LL;
typedef unsigned long long ULL;
const int    prime = 999983;
const int    INF = 0x7FFFFFFF;
const LL     INFF =0x7FFFFFFFFFFFFFFF;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-6;
const LL     mod = 1e9 + 7;
int dr[2][4] = {1,-1,0,0,0,0,-1,1};
typedef pair<int,int> P;

LL n;
bool judge(LL mid,LL n){
    LL ans = 0;
    while(mid > 0)
       ans += mid,mid >>= 1;
    return ans >= n; 
}
const LL inv2 = 500000004;

const int maxn = 1e6;
LL a[maxn];
LL an[maxn];
LL  F(LL n){

    if(n < 200){
         return a[n];
     }
     n--;

     LL l = 1,r = n;
     while(r >= l){
         LL mid = l+((r-l)>>1);
         if(!judge(mid,n))
            l = mid+1;
         else 
            r = mid-1;
     }
     LL ans = 0;
     LL num = 0;
     while( r > 0)
       num += r, r >>=1;
     num = n-num;
     ans = (num%mod*(l%mod))%mod;
     l--;
     LL tmp = 1;
     while(1){
          LL t = l/tmp;
          if(t & 1)
             t = t%mod*(((t+1)/2)%mod)%mod;
          else 
             t = (t/2)%mod*((t+1)%mod)%mod;
         ans = (ans+(t*(tmp%mod)%mod))%mod; 
         tmp <<= 1;
         if(tmp > l)
           break;
     }
    return (ans+1)%mod;
} 
int main(void)
{  
  a[1] =a[2]= 1;
  for(int i = 3;i < maxn; ++i)
     a[i] = (a[i-a[i-1]]+a[i-1-a[i-2]])%mod;

  for(int i = 1;i < maxn;++i)
     a[i] = (a[i] +a[i-1])%mod;


  int T;
  scanf("%d",&T);
  for(int i = 1;i <= T; ++i){
     scanf("%lld",&n);
     LL ans = F(n);
     printf("%lld\n",ans);
  } 


   return 0;
}

全部评论

相关推荐

最近又搬回宿舍了,在工位坐不住,写一写秋招起伏不断的心态变化,也算对自己心态的一些思考表演式学习从开始为实习准备的时候就特别焦虑,楼主一开始选择的是cpp后端,但是24届这个方向已经炸了,同时自己又因为本科非92且非科班,所以感到机会更加迷茫。在某天晚上用java写出hello&nbsp;world并失眠一整晚后选择老本行干嵌入式。理想是美好的,现实情况是每天忙但又没有实质性进展,总是在配环境,调工具,顺带还要推科研。而这时候才发现自己一直在表演式学习,徘徊在设想如何展开工作的循环里,导致没有实质性进展。现在看来当时如果把精力专注在动手写而不是两只手端着看教程,基本功或许不会那么差。实习的焦虑5月,楼主...
耶比:哲学上有一个问题,玛丽的房间:玛丽知道眼睛识别色彩的原理知道各种颜色,但是她生活在黑白的房间里,直到有一天玛丽的房门打开了她亲眼看到了颜色,才知道什么是色彩。我现在最大可能的减少对非工作事情的思考,如果有一件事困扰了我, 能解决的我就直接做(去哪里或者和谁吵架等等……),解决不了的我就不想了,每一天都是最年轻的一天,珍惜今天吧
投递比亚迪等公司10个岗位 > 秋招被确诊为…… 牛客创作赏金赛
点赞 评论 收藏
分享
10-09 00:50
已编辑
长江大学 算法工程师
不期而遇的夏天:1.同学你面试评价不错,概率很大,请耐心等待;2.你的排名比较靠前,不要担心,耐心等待;3.问题不大,正在审批,不要着急签其他公司,等等我们!4.预计9月中下旬,安心过节;5.下周会有结果,请耐心等待下;6.可能国庆节前后,一有结果我马上通知你;7.预计10月中旬,再坚持一下;8.正在走流程,就这两天了;9.同学,结果我也不知道,你如果查到了也告诉我一声;10.同学你出线不明朗,建议签其他公司保底!11.同学你找了哪些公司,我也在找工作。
点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务