链接: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
思路:这道题的规律真的是难想。
打表可知,a【i】的值就是i转化成二进制后,相邻两位的值相同就加一,否则减一。
然后就可以用数位dp来写了。
用dp【i】【j】【k】表示第i位,当前位的值是j,当前的和是k
由于k的取值范围是【-64,64】所以用abs(和-64)来代替。
#include <bits/stdc++.h>
using namespace std;
const long long mod=1000000007;
long long i,n,m,dp[64][3][128],a[64],T;
long long dfs(int len,bool maxi,int pre,int sum)
{
if( dp[len][pre][sum]!=-1 && maxi==0 )
return dp[len][pre][sum];
long long cnt=0;
if(!len)
return abs(sum-64);///他这里把和都变成了负数的绝对值
int maxn=maxi?a[len]:1;
for(int i=0;i<=maxn;i++)
{
if(pre==2)
{
if(i)
cnt+=dfs(len-1,maxi&&i==a[len],i,sum);
else
cnt+=dfs(len-1,maxi&&i==a[len],pre,sum);
}
else
{
if(i==pre)///判断%%%
cnt+=dfs(len-1,maxi&&i==a[len],i,sum+1);
else
cnt+=dfs(len-1,maxi&&i==a[len],i,sum-1);
}
}
cnt%=mod;
if(!maxi)
dp[len][pre][sum]=cnt;
return cnt;
}
long long div(long long tmp)
{
int p=0;
while(tmp)
a[++p]=tmp%2,tmp/=2;
return dfs(p,1,2,64);
}
int main()
{
memset(dp,-1,sizeof(dp));
scanf("%lld",&T);
while(T--)
{
scanf("%lld",&n);
printf("%lld\n",div(n));
}
return 0;
}
还有这篇博客讲的也很好。觉得这样写更自由https://blog.csdn.net/jaihk662/article/details/81263085