转载:https://blog.csdn.net/xianpingping/article/details/81292942
链接:https://www.nowcoder.com/acm/contest/142/C
来源:牛客网
Chiaki Sequence Reloaded
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
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
思路:这道题的规律真的是难想。
打表可知,a【i】的值就是i转化成二进制后,相邻两位的值相同就加一,否则减一。
然后就可以用数位dp来写了。
用dp【i】【j】【k】表示第i位,当前位的值是j,当前的和是k
由于k的取值范围是【-64,64】所以用abs(和-64)来代替。
采用数位DP的记忆化模板来写
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
LL dp[64][3][129];
int a[64];
LL dfs(int len,bool shangxian,int pre,int sum)
{
if(len == 0){
return abs(sum - 64);
}
if(!shangxian && dp[len][pre][sum] != -1){
return dp[len][pre][sum];
}
LL ans = 0;
int maxn = shangxian ? a[len] : 1;
for(int i = 0;i <= maxn;++i)
{
if(pre == 2){
if(i){
ans += dfs(len - 1,shangxian && i == a[len],i,sum);
}
else{
ans += dfs(len - 1,shangxian && i == a[len],pre,sum);
}
}
else{
if(i == pre){
ans += dfs(len - 1,shangxian && i == a[len],i,sum + 1);
}
else{
ans += dfs(len - 1,shangxian && i == a[len],i,sum - 1);
}
}
ans %= mod;
}
ans %= mod;
if(!shangxian){
return dp[len][pre][sum] = ans;
}
return ans;
}
LL solve(LL n)
{
int k = 0;
while(n)
{
a[++k] = n % 2;
n /= 2;
}
return dfs(k,true,2,64);
}
int main()
{
int t;
//dp初始化必须在这里,在其他地方会超时,因为t组数据中计算完一个可以为下一个提供用处
memset(dp,-1,sizeof(dp));
while(~scanf("%d",&t))
{
while(t--)
{
LL n;
scanf("%lld",&n);
printf("%lld\n",solve(n) % mod);
}
}
return 0;
}