[HDU6304][数学] Chiaki Sequence Revisited

-杭电多校2018第一场G


题目描述

现在抛给你一个数列\(A\)

\[a_n=\begin{cases}1 & n = 1,2 \\ a_{n - a_{n-1}} + a_{n-1 - a_{n-2}} & n \ge 3\end{cases}
\]

现在需要你计算它的前缀和 \(\sum\limits_{i=1}^{n}a_i \ mod \ (10^9+7)\)

数据范围 \(n(1\le n\le 10^{18})\)

题目分析

不可描述的做法

拿到题目第一步对序列\(A\)打一个100的表,对吧,然后 "OEIS" 一下,发现真的有

http://oeis.org/A046699

\(a[1..] = {1,2,2,3,4,4,4,5,6,6,7,8,8,8,8,9,....}\)

结果发现并没有什么用,既没有通项公式,更别说求和公式了。

大概正确的规律

可以发现每种数字的出现次数是由规律可循的,\(1\)出现了\(1\)次,\(2\)出现了\(2\)次,\(3\)出现了\(1\)次

我们设\(f(x)\)代表数字\(x\)出现的次数

那么 \(f[1..] = {1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,....}\)

通过观察100项的表可以的出一个大概正确的规律,数字\(x\)会出现\(1+log_2lowbit(x)\)次

至于\(lowbit(x)\) 是啥,可以去了解一下树状数组,表示 \(\min\{2^k:2^k|x\}\)

经过总结规律可以发现递推式,那么有

\[\begin{cases} {f(2k+1) =1 }\\\\f(2k)=f(k)+1\end{cases}
\]

也就是 http://oeis.org/A001511 中提到的数列,但是知道出现次数并没有什么用,我们需要计算的是\(f(x)\)

的前缀和,这样我们就可以知道\(n\)位置上表示的数字的值,即\(a_n\)的值。

我们设 $g(n) = \sum^{n}_{i=1}f(i) $ ,可以简单推导一下

\[\begin {align}
&g(n) = \sum_{k=1}^{n}f(k) \\
&g(n) = \sum^{\lfloor \frac{n-1}{2}\rfloor}_{k=0}f(2k+1) + \sum^{\lfloor \frac{n}{2}\rfloor}_{k=1}f(2k)\\
&g(n) = \Big\lceil\frac{n}{2}\Big\rceil + \sum^{ \lfloor \frac{n}{2}\rfloor}_{k=1} \{f(k)+1\}\\
&g(n) = \Big\lceil\frac{n}{2}\Big\rceil + \Big\lfloor\frac{n}{2}\Big\rfloor + g(\Big\lfloor\frac{n}{2}\Big\rfloor) \\
&g(n) = g(\Big\lfloor\frac{n}{2}\Big\rfloor)+n \\
\end {align}
\]

也就是说我们现在可以在\(O(\log N)\)时间计算出\(g(n)\) ,由于该函数显然是单调的,那么我们现在可以通过二分求得\(a_n\)对应的值,即 \(a_n = \min\{k\ |\ g(k)\ge n\}\)。

然而题目要我们求前缀和,那么问题来了,我们现在计算单个值就需要\(O(\log^2N )\)时间

如何计算出前缀和呢?考虑通过每个数字的出现次数入手。

\[\begin{matrix}
1, 3, 5, 7, 9, \cdots ,2(t-1)+1 &\quad\quad\text{分别出现一次} \\
2,6,10,14,18, \cdots ,4(t-1)+2 &\quad\quad\text{分别出现两次} \\
4,12,20,28,36,\cdots,8(t-1)+4 &\quad\quad\text{分别出现三次} \\
\vdots &\vdots\\
\cdots 2^k(t-1)+2^{k-1} &\quad\quad\text{分别出现$k$次}
\end{matrix}
\]

由于每一行都相当于一个等差数列,现在的目标就是找到每一行的末项就好了。

也就是找到__最后一个小于\(a_n\)的值__,再用等差数列求和公式\(O(1)\)计算出每一行的值,最后所有行加起来就是答案的主要部分了。

会发现经过上面的计算所有等于\(a_n\)的项没有计算入答案,我们只要计算出等于\(a_n\)的有多少项,最后再累加到答案,这道题就做完了。容易得到 \(a_n\)需要计算\(n-g(a_n-1)\)次。根据最开始我对数列的偏移,正确的答案还需要再+1。整体复杂度为\(O(\log^2N+logN)\)

注:计算\(a_n\)需要 \(O(\log^2N)\)时间,需要估计二分上下界,否则会超时。

无比准确的题解

以下是多校官方给的题解。

考虑这个数列的差分数列,除了个别项,本质就是:\(1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0,...\)。

可以观测到,这个序列可以这么生成:一开始只有一个\(1\),\(1\)变成\(110\),\(0\)保持不变。迭代无穷多次后就是这个差分序列。

知道差分序列,可以应用阿贝尔变换,把\(a\)的前缀和搞成差分序列相关。不妨令差分序列是\(da\),那么\(a\)的前缀和$$s(n)=(n-1)\sum_{i=0}^{n-2}da(i) - \sum_{i=0}^{n-2}da(i)i + 1$$。

利用\(da\)的分形结构,很容易算出\(s(n)\)。

代码Code

/*
[HDU6304][数学]
Chiaki Sequence Revisited
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD = 1e9+7;
const int inv2 = 500000004;
int T;
LL n;
LL calc(LL n) {
if(n<=1) return n;
else return calc(n/2)+n;
}
void solve() {
LL l=n/2-30,r=n/2+30,m,p=-1;
//需要预先估计上下界减少二分次数,否则会TLE.
while(l<=r) {
m = (l+r)/2;
if(calc(m)>n) r=m-1;
else l=m+1,p=m;
}
LL rest = ((n - calc(p))%MOD+MOD)%MOD;
LL ans = 0, s, t, e, k, c=1, x, y;
for(LL i=1;; i<<=1,c++) {
if(i>p) break;
x = i%MOD;
y = 2*i%MOD;
s = x;
k = ((p-i)/(2*i)+1)%MOD;
e = (y*(k-1)%MOD+i)%MOD;
ans = (ans+c*(s+e)%MOD*k%MOD*inv2%MOD)%MOD;
}
ans = (ans + rest*((p+1)%MOD)%MOD)%MOD;
printf("%lld\n",ans+1);
}
int main() {
scanf("%d",&T);
while(T--) {
scanf("%lld",&n);
n--; //偏移一项
solve();
}
return 0;
}

[HDU6304][数学] Chiaki Sequence Revisited-杭电多校2018第一场G的更多相关文章

  1. HDU 5724 Chess (状态压缩sg函数博弈) 2016杭电多校联合第一场

    题目:传送门. 题意:有n行,每行最多20个棋子,对于一个棋子来说,如果他右面没有棋子,可以移动到他右面:如果有棋子,就跳过这些棋子移动到后面的空格,不能移动的人输. 题解:状态压缩博弈,对于一行2^ ...

  2. 可持久化线段树的学习(区间第k大和查询历史版本的数据)(杭电多校赛第二场1011)

    以前我们学习了线段树可以知道,线段树的每一个节点都储存的是一段区间,所以线段树可以做简单的区间查询,更改等简单的操作. 而后面再做有些题目,就可能会碰到一种回退的操作.这里的回退是指回到未做各种操作之 ...

  3. 杭电多校第七场 1010 Sequence(除法分块+矩阵快速幂)

    Sequence Problem Description Let us define a sequence as below f1=A f2=B fn=C*fn-2+D*fn-1+[p/n] Your ...

  4. 杭电多校第七场-J-Sequence

    题目描述 Let us define a sequence as belowYour job is simple, for each task, you should output Fn module ...

  5. 2017杭电多校第七场1011Kolakoski

    Kolakoski Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others) Tota ...

  6. HDU 5745 La Vie en rose (DP||模拟) 2016杭电多校联合第二场

    题目:传送门. 这是一道阅读理解题,正解是DP,实际上模拟就能做.pij+1 指的是 (pij)+1不是 pi(j+1),判断能否交换输出即可. #include <iostream> # ...

  7. HDU 5744 Keep On Movin (贪心) 2016杭电多校联合第二场

    题目:传送门. 如果每个字符出现次数都是偶数, 那么答案显然就是所有数的和. 对于奇数部分, 显然需要把其他字符均匀分配给这写奇数字符. 随便计算下就好了. #include <iostream ...

  8. HDU 5742 It's All In The Mind (贪心) 2016杭电多校联合第二场

    题目:传送门. 题意:求题目中的公式的最大值,且满足题目中的三个条件. 题解:前两个数越大越好. #include <iostream> #include <algorithm> ...

  9. HDU 5734 Acperience (公式推导) 2016杭电多校联合第二场

    题目:传送门. #include <iostream> #include <algorithm> #include <cstdio> #include <cs ...

随机推荐

  1. Sonarqube中文插件-Linux[20180105]

    前言     上次安装了Sonarqube英文版使用起来不方便,这次为Sonarqube安装中文插件. 前期准备:     软件下载: https://github.com/SonarQubeComm ...

  2. LeetCode 删除链表倒数第N个节点

    基本思路 定义两个指示指针a b 让a先行移动n+1个位置 若a指向了NULL的位置,则删除的是头节点(由于走过了n+1个节点刚好指在尾部的NULL上) 否则让b与a一起移动直至a->next, ...

  3. Cygwin安装篇,windows平台上运行的类UNIX模拟环境

    1.虚拟光驱的安装 虚拟光驱下载 一路下一步,不再阐述,这些广告选项不要选 2.安装文档,双击ISO文档 ISO下载地址 链接:http://pan.baidu.com/s/1miFVCYO 密码:z ...

  4. ThinkPHP之__construct()和__initialize()

    ThinkPHP中的__initialize()和类的构造函数__construct()网上有很多关于__initialize()的说法和用法,总感觉不对头,所以自己测试了一下.将结果和大家分享.不对 ...

  5. ECSHOP和SHOPEX快递单号查询韵达插件V8.6专版

    发布ECSHOP说明: ECSHOP快递物流单号查询插件特色 本ECSHOP快递物流单号跟踪插件提供国内外近2000家快递物流订单单号查询服务例如申通快递.顺丰快递.圆通快递.EMS快递.汇通快递.宅 ...

  6. Win7下如何安装python pygame的whl包

    看了小甲鱼的python教程,对那个python版本的打飞机游戏很感兴趣,尝试运行,居然报错了,提示缺少pygame包: 仔细一看需要安装一个pygame的包,默认安装好python是不包括这个包的, ...

  7. python并发编程之多进程、多线程、异步、协程、通信队列Queue和池Pool的实现和应用

    什么是多任务? 简单地说,就是操作系统可以同时运行多个任务.实现多任务有多种方式,线程.进程.协程. 并行和并发的区别? 并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任 ...

  8. atoi 和 atof (把数字字符串转化为数字储存)

    int atoi(char *s) 如果字符串内容是整数就返回该整数,否则返回0 double atof(char *s) 同上,不过返回浮点型 #include<iostream> #i ...

  9. Black And White (DFS 训练题)

    G - Black And White ================================================================================ ...

  10. List排序方法

    可用使用Collections.sort(List<T> list)和Collections.sort(List<T> list, Comparator<? super ...