牛客网暑期ACM多校训练营(第四场)C:Chiaki Sequence Reloaded(数位DP)

链接:https://www.nowcoder.com/acm/contest/142/C

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
Chiaki is interested in an infinite sequence a1,a2,a3,..., a 1 , a 2 , a 3 , . . . , which defined as follows:
牛客网暑期ACM多校训练营(第四场)C:Chiaki Sequence Reloaded(数位DP)_第1张图片
Chiaki would like to know the sum of the first n terms of the sequence, i.e. ni=1|ai| ∑ i = 1 n | a i | . As this number may be very large, Chiaki is only interested in its remainder modulo (109+7) ( 10 9 + 7 ) .
输入描述:
There are multiple test cases. The first line of input contains an integer T(1T105) T ( 1 ≤ T ≤ 10 5 ) , indicating the number of test cases. For each test case:
The first line contains an integer n(1n1018) n ( 1 ≤ n ≤ 10 18 ) .
输出描述:
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

这里写图片描述
令n的二进制表示为b(m)b(m-1)…b(0),且b(m)=1
p(n)是b(i)=b(i+1)的i个数,q(n)是b(i) != b(i+1)的i个数
可以发现| an|=|p(n)+1q(n)| a n | = | p ( n ) + 1 − q ( n ) |
例如 a2 a 2 2=(10)2 2 = ( 10 ) 2 ,则 p2=0q2=2 p 2 = 0 , q 2 = 2 |a2|=|0+12|=1 | a 2 | = | 0 + 1 − 2 | = 1
a3 a 3 3=(11)2 3 = ( 11 ) 2 ,则 p3=1q2=1 p 3 = 1 , q 2 = 1 |a3|=|1+11|=1 | a 3 | = | 1 + 1 − 1 | = 1
之后考虑数位dp计算 ni=1|pi+1qi| ∑ i = 1 n | p i + 1 − q i |

#include
using namespace std;
const int MAX=2e5+10;
const int MOD=1e9+7;
typedef long long ll;
inline ll read()
{
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
int p[65];
ll d[65][2][65][65];//d[i][j][p][q]表示在第i位为j的数x中,满足p(x)=p,q(x)=q的数的个数
ll sum[65];
ll cal(ll x)
{
    int n=0;
    while(x)p[++n]=x%2,x/=2;
    ll ans=0;
    int a=0,b=0;
    for(int i=n;i>=1;i--)
    {
        if(i==n){b++;continue;}
        for(int j=0;j<=i;j++)
        {
            if(d[i][0][j][i-j]&&p[i]==1)
            {
                if(p[i+1]==0)ans+=abs(j+a+1-(i-j+b))*d[i][0][j][i-j]%MOD;
                else ans+=abs(j+a-(i-j+b+1))*d[i][0][j][i-j]%MOD;
                if(ans>=MOD)ans%=MOD;
            }
        }
        ans+=sum[i];
        if(ans>=MOD)ans%=MOD;
        if(p[i+1]==p[i])a++;
        else b++;
    }
    ans+=abs(a+1-b);
    if(ans>=MOD)ans%=MOD;
    return ans;
}
int main()
{
    memset(d,0,sizeof d);
    memset(sum,0,sizeof sum);
    for(int i=1;i<=64;i++)
    {
        if(i==1)
        {
            d[i][0][1][0]=1;
            d[i][1][0][1]=1;
            continue;
        }
        for(int j=0;j<=i;j++)
        {
            if(j1][j][i-j]+=d[i-1][1][j-1][i-j];
            if(i>=j+2)d[i][1][j][i-j]+=d[i-1][0][j+1][i-2-j];
            if(j)d[i][0][j][i-j]+=d[i-1][1][j-1][i-j];
            if(j)d[i][0][j][i-j]+=d[i-1][0][j-1][i-j];
            if(d[i][1][j][i-j]>=MOD)d[i][1][j][i-j]%=MOD;
            if(d[i][0][j][i-j]>=MOD)d[i][0][j][i-j]%=MOD;
        }
        for(int j=0;j<=i;j++)//这里不预处理一下会T。。。
        {
            sum[i]+=abs(j+1-(i-j))*d[i][1][j][i-j]%MOD;
            sum[i]%=MOD;
        }
    }
    int T;
    cin>>T;
    while(T--)
    {
        ll n=read();
        printf("%lld\n",cal(n));
    }
    return 0;
}

你可能感兴趣的:(数位DP)