1. 程式人生 > >牛客網暑期ACM多校訓練營(第四場)C. Chiaki Sequence Reloaded 數位DP

牛客網暑期ACM多校訓練營(第四場)C. Chiaki Sequence Reloaded 數位DP

Problem C. Chiaki Sequence Reloaded

Input file: standard input
Output file: standard output
Time limit: 1 seconds
Memory limit: 256 mebibytes

Problem Description

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).

Input

There are multiple test cases. The first line of input contains an integer T (1 ≤ T ≤ 10^5), indicating the number of test cases. For each test case:
The first line contains an integer n (1 ≤ n ≤ 10^18).

Output

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

Sample Input Sample Output
10
1
2
3
4
5
6
7
8
9
10
0
1
2
2
4
4
6
7
8
11




觀察給出的遞推公式,發現

a i a i 2 = 1 i 二進位制的後兩位相等
a i a i 2 = 1 i 二進位制的後兩位不等
由此,可以對小於 n 的元素做數位DP。
設dp[len][last][sum]表示當前dp到第len位,最後一位二進位制位是last,且之前dp的數位對答案的貢獻和是sum.
則可以很容易的用數位DP算出答案。

#include <cstdio>
#include <iostream>
#include <string.h>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define pb push_back
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
typedef pair<int,int> pp;
const int maxn=105,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f,mod=1e9+7;
const ld pi=acos(-1.0L);
ll dp[75][2][150],num[100];

ll dfs(ll len,ll last,ll sum,bool HaveLimit,bool zero) {
    if (!len)
        if (!zero) return 0; else return abs(sum);
    if (!HaveLimit&&dp[len][last][sum+64]!=-1&&zero)
        return dp[len][last][sum+64];

    int limit,i,ext;
    if (HaveLimit) limit=num[len]; else limit=1;
    ll ans=0;
    for (i=0;i<=limit;i++) {
        if (!zero) ext=0; else if (i==last) ext=1; else ext=-1;
        ans+=dfs(len-1,i,sum+ext,HaveLimit&&i==limit,zero|i);
        ans%=mod;
    }
    if (!HaveLimit&&zero) dp[len][last][sum+64]=ans;
    return ans;
}

ll solve(ll limit) {
    if (limit==-1) return 0;
    ll k=limit,cnt=0;
    while (k>0) {
        cnt++;
        num[cnt]=k%2;
        k/=2;
    }
    ll ans=0;
    ans=dfs(cnt,2,0,1,0);
    return ans;
}

int main() {
    int cas;
    scanf("%d",&cas);
    memset(dp,-1,sizeof(dp));
    while (cas--) {
        ll n;
        scanf("%lld",&n);
        ll ans=solve(n);
        printf("%lld\n",ans);
    }
    return 0;
}