题目链接 : http://acm.hdu.edu.cn/showproblem.php?pid=6304
多校contest1
 
Problem Description

Chiaki is interested in an infinite sequence a1,a2,a3,..., which is defined as follows:

an={1an−an−1+an−1−an−2n=1,2n≥3

Chiaki would like to know the sum of the first n terms of the sequence, i.e. ∑i=1nai. As this number may be very large, Chiaki is only interested in its remainder modulo (109+7).

Input
There are multiple test cases. The first line of input contains an integer T (1≤T≤105), indicating the number of test cases. For each test case:
The first line contains an integer n (1≤n≤1018).
 
Output

For each test case, output an integer denoting the answer.

 题目大意是求一个 奇怪序列的 前 n 项 和,n最坏情况达 1e18。
开始打了个表,发现在序列是从1开始的连续整数(每个整数出现的次数不同),除了数字 1是出现两次,其他数字 如x 都是出现 lowbit(x)后缀0的个数+1 次。 如2(10) 出现2次 ,3(11) 出现1次,4(100) 出现3次,5(101)出现1次,6(110) 出现2次...
可以发现这是一个十分有特点的(类似2进制,有部分对称性)的序列
接下来我们可以发现如果把1当做出现1次,出现在 2^n 上,如果占满 ,次数总和刚好是 2^(n+1) -1 次,那么多出来的数似乎又没有规律了,这时我们可以利用局部对称与这个和二进制相似的特点,找到 第 n 个数 是数字多少(落在图中的位置),
有两种方法:
第一种 可以知道N(自减一后)对应的准确数字,但不知N落在的数字差几次被填满,不便计算。
 void init(){
P[]=;P[]=;
nP[]=;nP[]=;
for(int i=;i<=;++i){
P[i]=*P[i-];
nP[i]=P[i]-;
}
} ll getbound(ll N){
ll bound=;
for(int i=;i>=;--i){
while(N>=nP[i]){
N-=nP[i];
bound+=P[i-];
}
}
return bound;
}

第二种 完全参照二进制,可知N(自减一后)所落在的数字最近的次数填满数字,后来计算时很方便。

 void init(){
P[]=;P[]=;
nP[]=;nP[]=;
for(int i=;i<=;++i){
P[i]=*P[i-];
nP[i]=P[i]-;
}
} ll getbound(ll& N){
ll bound=;
for(int i=;i>=;--i){
if(N>=nP[i]){
N-=nP[i];
bound+=P[i-];
}
}
return bound;
}

计算时可以可利用每个数字出现的次数,是1(2^0)的倍数的出现过一次,是2(2^1)的倍数的额外出现过一次,是4(2^2)的倍数的又额外出现一次,,,(这也恰恰是后缀0的意义)

在这里贴两份按照上述两种方法写的代码。

 #include <bits/stdc++.h>
using namespace std; typedef long long ll; const ll MOD=1e9+;
ll P[];
ll nP[];
ll a[];
ll arr[]; ll lowbit(ll x){
ll low=x&(-x);
ll cnt=;
while(low>>=){
cnt++;
}
return cnt;
} void init(){
P[]=;P[]=;
nP[]=;nP[]=;
for(int i=;i<=;++i){
P[i]=*P[i-];
nP[i]=P[i]-;
} //a[1]=1;a[2]=1;
//arr[1]=1;arr[2]=2;
//for(int i=3;i<101;i++){
// a[i]=a[i-a[i-1]]+a[i-1-a[i-2]];
// arr[i]=arr[i-1]+a[i];
//} //for(int i=1;i<101;++i) printf("%lld\n",arr[i]); } ll inv(ll a,ll m){
if(a==) return ;
return inv(m%a,m)*(m-m/a)%m;
} ll getbound(ll N){
ll bound=;
for(int i=;i>=;--i){
while(N>=nP[i]){
N-=nP[i];
bound+=P[i-];
}
}
return bound;
} int main(){
//freopen("data.in","r",stdin);
//freopen("data1.out","w",stdout);
init();
int T;
scanf("%d",&T);
while(T--){
ll N;
scanf("%lld",&N);
if(N==) puts("");
else{
ll ans=;
N-=1ll;
ll bound=;
bound=getbound(N);
//printf("bound = %lld\n",bound);
ll cnt=lowbit(bound)+1ll;
ll tot=N;
for(ll i=;i<=cnt;++i){
if(bound==getbound(N+i)) tot++;
else break;
}
ll _m2=inv(,MOD);
//printf("%lld\n",_m2);
for(int i=;i<=;++i){
if(P[i]<=bound){
ll M=bound/P[i];
ans=(ans+(P[i]%MOD)*(M%MOD)%MOD*((M+1ll)%MOD)%MOD*_m2%MOD)%MOD;
}
else break;
}
//printf("1:%lld\n",(ans+1)%MOD);
ans=(ans-(bound)*(tot-N)%MOD+MOD)%MOD;
printf("%lld\n",(ans+1ll)%MOD);
//printf("%I64d %I64d\n",(ans+1ll)%MOD,arr[N+1]);
//最后加一
}
}
return ;
}
 #include <bits/stdc++.h>
using namespace std; typedef long long ll; const ll MOD=1e9+;
ll P[];
ll nP[];
ll a[];
ll arr[]; ll lowbit(ll x){
ll low=x&(-x);
ll cnt=;
while(low>>=){
cnt++;
}
return cnt;
} void init(){
P[]=;P[]=;
nP[]=;nP[]=;
for(int i=;i<=;++i){
P[i]=*P[i-];
nP[i]=P[i]-;
} //a[1]=1;a[2]=1;
//arr[1]=1;arr[2]=2;
//for(int i=3;i<101;i++){
// a[i]=a[i-a[i-1]]+a[i-1-a[i-2]];
// arr[i]=arr[i-1]+a[i];
//} //for(int i=1;i<101;++i) printf("%lld\n",arr[i]); } ll inv(ll a,ll m){
if(a==) return ;
return inv(m%a,m)*(m-m/a)%m;
} ll getbound(ll& N){
ll bound=;
for(int i=;i>=;--i){
if(N>=nP[i]){
N-=nP[i];
bound+=P[i-];
}
}
return bound;
} int main(){
//freopen("data.in","r",stdin);
//freopen("data1.out","w",stdout);
init();
int T;
scanf("%d",&T);
while(T--){
ll N;
scanf("%lld",&N);
if(N==) puts("");
else{
ll ans=;
N-=1ll;
ll bound=;
bound=getbound(N);
//printf("bound = %lld\n",bound);
//ll cnt=lowbit(bound)+1ll;
//ll tot=N;
//for(ll i=1;i<=cnt;++i){
// if(bound==getbound(N+i)) tot++;
// else break;
//}
ll _m2=inv(,MOD);
for(int i=;i<=;++i){
if(P[i]<=bound){
ll M=bound/P[i];
ans=(ans+(P[i]%MOD)*(M%MOD)%MOD*((M+1ll)%MOD)%MOD*_m2%MOD)%MOD; }
else break;
}
//printf("1:%lld\n",(ans+1)%MOD);
ans=(ans+(bound+)*N%MOD)%MOD;
printf("%lld\n",(ans+1ll)%MOD);
//printf("%I64d %I64d\n",(ans+1ll)%MOD,arr[N+1]);
//最后加一
}
}
return ;
}

然后,比赛时WA了两发,其实规律找到了,但错在了计算,算总和时,第一个错误处是没用逆元,第二个错误处是P[i]在N为1e18时奇大,应该先mod在相乘。

血的教训。

Chiaki is interested in an infinite sequence a1,a2,a3,..., which is defined as follows:

an={1an−an−1+an−1−an−2n=1,2n≥3

Chiaki would like to know the sum of the first n terms of the sequence, i.e. ∑i=1nai. As this number may be very large, Chiaki is only interested in its remainder modulo (109+7).

HDU 6304 Chiaki Sequence Revisited的更多相关文章

  1. 2018 杭电多校1 - Chiaki Sequence Revisited

    题目链接 Problem Description Chiaki is interested in an infinite sequence $$$a_1,a_2,a_3,...,$$$ which i ...

  2. HDU - 6304(2018 Multi-University Training Contest 1) Chiaki Sequence Revisited(数学+思维)

    http://acm.hdu.edu.cn/showproblem.php?pid=6304 题意 给出一个数列的定义,a[1]=a[2]=1,a[n]=a[n-a[n-1]]+a[n-1-a[n-2 ...

  3. Chiaki Sequence Revisited HDU - 6304 lowbit找规律法

    Problem Description Chiaki is interested in an infinite sequence a1,a2,a3,..., which is defined as f ...

  4. 【HDOJ6304】Chiaki Sequence Revisited(数学)

    题意:给定一个序列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<=1e1 ...

  5. [HDU6304][数学] Chiaki Sequence Revisited-杭电多校2018第一场G

    [HDU6304][数学] Chiaki Sequence Revisited -杭电多校2018第一场G 题目描述 现在抛给你一个数列\(A\) \[ a_n=\begin{cases}1 & ...

  6. HDU 5860 Death Sequence(死亡序列)

    p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-s ...

  7. HDU 1711 Number Sequence(数列)

    HDU 1711 Number Sequence(数列) Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Ja ...

  8. HDU 1005 Number Sequence(数列)

    HDU 1005 Number Sequence(数列) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Jav ...

  9. HDU 5860 Death Sequence(递推)

    HDU 5860 Death Sequence(递推) 题目链接http://acm.split.hdu.edu.cn/showproblem.php?pid=5860 Description You ...

随机推荐

  1. Linux cp命令详解

    Linux cp命令 Linux cp命令主要用于复制文件或目录,将源文件复制至目标文件,或将多个源文件复制至目标目录 用法: cp [选项]... [-T] 源文件 目标文件 cp [选项]... ...

  2. C++笔记(1)

    C++笔记1文件与流笔记 参考博客: https://blog.csdn.net/kingstar158/article/details/6859379       关闭文件中: 当文件读写操作完成之 ...

  3. mysql 远程备份

    #远程备份./innobackupex --defaults-file=/etc/my.cnf --no-timestamp --user xxx --host 192.168.1.123 \--pa ...

  4. instant client 的配置

    instant client 的配置 oracle server developer自带了客户端 解压目录:D:\Toolkit\instantclient_11_2 设置环境变量 Ø  在Path变 ...

  5. SpringMVC复习

    第一天 springmvc.xml 一个配置文件,SpringMVC本身就是Spring的子项目,对Spring兼容性很好,不需要做很多配置. 这里只配置一个Controller扫描就可以了,让Spr ...

  6. java基础-反射(细节)

    java面试题--java反射机制? Java反射机制的作用:1)在运行时判断任意一个对象所属的类.2)在运行时判断任意一个类所具有的成员变量和方法.3)在运行时任意调用一个对象的方法4)在运行时构造 ...

  7. C#将对象序列化成JSON字符串

    C#将对象序列化成JSON字符串 public string GetJsonString() { List<Product> products = new List<Product& ...

  8. JS基础——变量

    引用类型:对象  数组 函数 }; var b =a ; b.age = ; console.log(a.age);// 21 传递的是地址, a,b同地址 值类型: var a =100; var ...

  9. 第二章 FFmpeg常用命令

    2.1 FFmpeg常见的命令大概分为6个部分 ffmpeg信息查询部分 公共操作参数部分 文件主要操作参数部分 视频操作参数部分 字幕操作参数部分 2.1.1 FFmpeg的封装转换 FFmpeg ...

  10. Kafka介绍与消息队列

    消息队列的好处: 消息队列(Message Queue) 消息: 网络中的两台计算机或者两个通讯设备之间传递的数据.例如说:文本.音乐.视频等内容. 队列:一种特殊的线性表(数据元素首尾相接),特殊之 ...