Luogu | P1762 偶数 | 数论 / 动态规划 | Lucas 定理 + 数位


Description

给定一个正整数 $N$ ,请输出杨辉三角形前 $N$ 行的偶数个数$\mod 1000003$ 的结果。


Input Format

一行一个正整数 $N$ 。


Output Format

一行一个正整数,表示结果。


Input Sample

Sample 01

6


Output Sample

Sample 01

6


Data Range

$ 1 \le N \le 10^{15}$


Solution

根据 Lucas 定理,当 p 为质数时有:$\binom{n}{m} \equiv \binom{n \div p}{m\div p} \times \binom{n \mod p}{m \mod p} (\mod p)$。

这里的 p = 2 ,那么可以发现最后 $\binom{n}{m} \mod 2$ 的值其实为 nm 二进制按位分解的组合数的乘积 $\mod 2$ 。

又因为有

$$\binom{0}{0} = 1$$

$$\binom{0}{1} =0$$

$$\binom{1}{0} = 1$$

$$\binom{1}{1} = 1$$

那么可以发现,在上述四式中,m & n == m 等价于 $\binom{n}{m} = 1$。

这意味着,在原式中有 m & n ==m 等价于 $\binom{n}{m} \mod 2 =1$。

则杨辉三角形的第 $x$ 行的奇数个数为$\sum_{i=1}^{x} ((i \ \& \ x) == i) $。对于 $x$ ,对 $x$ 进行二进制分解,假设可以得到 $k$ 个 1 ,那么这 $k$ 个位置的 1 对应的组合数中的 $m$ 的该位上的数字可以为 1 或者 0 两种选法,可得 $x$ 对答案的贡献为 $(\sum_{i=1}^{x} ((i \ \& \ x) == i)) = 2^k$ 。

考虑计算出 ≤ N 的所有数字对于答案的贡献。这个过程可以用 数位 dp 计算出 $\sum$ **≤ N 的数字中所有数字的二进制分解的 1 的个数为 k 的数字的个数 × 2k ** 完成。

注意中途的 long long


Code

#include<cstdio>
#include<cstdlib>
#include<cstring>

#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
#define swap(x,y) {int t=x; x=y,y=t;}
#define wipe(x,y) memset(x,y,sizeof(x))
#define dbgIn(x) freopen(x".in","r+",stdin)
#define rep(x,y,z) for(int x=y,I=z;x<=I;++x)
#define dbgOut(x) freopen(x".out","w+",stdout)
#define file(x) freopen(x".in","r+",stdin); freopen(x".out","w+",stdout)

#define mo 1000003

inline void Read(int &x){
    x=0; char ch=0; while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar(); return;
}

int len;

long long N;

int tmp[65];
int res[65];
int sum[65];

long long F[65][65];

void Decompose(long long X){
    while(X){
        tmp[++len]=X%2;
        X/=2;
    }
    rep(i,1,len)
        res[i]=tmp[len-i+1];
    return;
}

void Prec(){
    F[0][0]=1;
    rep(i,1,63){
        rep(j,0,i){
            F[i][j]=F[i-1][j];
            if(j>=1)
                F[i][j]=(F[i][j]+F[i-1][j-1])%mo;
        }
    }
}

long long Calc(long long X){
    long long ret=0;
    Decompose(X);
    rep(i,1,len)
        sum[i]=sum[i-1]+res[i];
    rep(i,1,len){
        rep(j,0,res[i]-1){
            rep(k,0,len-i)
                ret=(ret+(F[len-i][k]%mo)*((long long)1<<(k+sum[i-1]))%mo)%mo;
        }
    }
    return ret;
}

int main(){
    Prec();
    scanf("%lld",&N);
    printf("%lld\n",((((((N+1)%mo)*(N%mo)/2)-Calc(N)))%mo+mo)%mo);
    return 0;
}