链接:https://www.nowcoder.com/acm/contest/142/C
来源:牛客网
题目描述
Chiaki is interested in an infinite sequence a1, a2, a3, ..., which defined as follows:
Chiaki would like to know the sum of the first n terms of the sequence, i.e. . As this number may be very large, Chiaki is only interested in its remainder modulo (109 + 7).
输入描述:
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).
输出描述:
For each test case, output an integer denoting the answer.
示例1
输入
复制
10 1 2 3 4 5 6 7 8 9 10
输出
复制
0 1 2 2 4 4 6 7 8 11
[思路]
S(n) = : 1,3,6,10,15,21; 可以发现, 以4 为周期, 前两项 使 S(n) 为 -1 , 后两项 使S(n) 为 1
然后 在看通项:
=
+ S(n)
= + S(n/2) + S(n)
= .....
= S(n) + S(n/2) + S(n/4) + S(n/8) +..... +a[1]; a[1] = 0;
对于 an ; 我们看 二进制下形式; 例如 12 : 1100 = S(1100) + S(110) + S(11) 统计末位 相邻的两位: 如果 是 10 或者 01
则使 S(x) = -1, else S(x) = 1;
故得出一个结论 : an = (所有相邻的两位相同的个数) -
(所有相邻的两位不相同的个数)
然后 构建一个 完全二叉树
然后 利用 数位DP ,DFS 搜每一个 二进制位, 相当于把1-n,全都扫描了一遍 ,
记录 前一个 front 与 现在这个 , 以及 前一个的limit 做限制 ,跑DFS,在
如果 前一个 为 0 , 那么 后面的数 最大可以为 1, 如果 前面为1, 则后面的数要在限制之内
回溯的时候记录答案
[代码]
#include <iostream>
#include <bits/stdc++.h>
#define rep(i,a,n) for(int i = a; i < n ; i++)
#define per(i,a,n) for(int i = n-1; i>=a;i--)
typedef long long ll;
using namespace std;
const int mod = 1e9+7;
ll dp[100][3][200];
int dig[100];
int cot;
int judge(int i,int fro)
{
return i==fro ? 1:-1;
}
ll dfs(int pos,int lim,int num,int fro)
{
if(pos<0)
return abs(64-num);
if(!lim&&dp[pos][fro][num]!=-1)
return dp[pos][fro][num];
int ed = lim ? dig[pos] : 1;
ll ans = 0 ;
for(int i = 0 ; i<=ed ;i++)
{
if( fro== 2 && i==0)
ans += dfs(pos-1,lim&(i==ed),num,2);
else if( fro == 2 && i==1)
ans += dfs(pos-1,lim&(i==ed),num,i);
else
ans += dfs(pos-1,lim&(i==ed),num+judge(i,fro),i);
ans %= mod;
}
if( !lim)
dp[pos][fro][num] = ans;
return ans;
}
int main()
{
ll n;
int T;
scanf("%d",&T);
memset(dp,-1,sizeof(dp));
while(T--)
{
memset(dig,0,sizeof(dig));
scanf("%lld",&n);
cot = 0;
while(n)
{
dig[cot++] = n%2;
n/=2;
}
printf("%lld\n",dfs(cot-1,1,64,2));
}
return 0;
}