P1762 偶数

我爱数学,但这个我没有用数学做,数学题单里发现的。

题意

求杨辉三角前 \(n\) 行的偶数个数,\(n\le10^{15}\)

这个正解是找规律,可是愚蠢的我怎么能轻易找出来,所以还是去想正常的分析。

众所周知,杨辉三角的第 \(x\) 行,第 \(y\) 列的数字是 \(\binom{x-1}{y-1}\),为了方便我们接下来将所有的行数列数统统减一。

那麽我们要求的是 \(\binom{x}{y}=0 \mod2\) 的个数。

根据卢卡斯定理我们一拆就会发现这个实际上就是把 \(x,y\) 进行二进制拆分,如果但凡有一次出现 \(\binom{0}{1}\),整个就是 0, 反之都是 1。

但是这个似乎不太适合直接全求出来,我们考虑能不能求 \(\binom{x}{y}=1 \mod2\)

这个简单,上边不都说了只有一种情况才会是 0, 我们枚举 \(x\),从 \(0\)\(n-1\),对于其中每一个数字求二进制下 \(1\) 的个数,贡献是 \(2^{popcount(x)}\)

我们只需要求解 \(\sum_{i=0}^{n-1}2^{popcount(i)}\),这个很明显可以使用数位 dp 求解,最后总体减去这个就行了。

注意算整体的等差数列不可以直接除以2,要逆元。

代码:

点击查看代码
#include <bits/stdc++.h>
#define int unsigned long long
using namespace std;
const int mod=1000003;
const int inv2=(mod+1)/2;
int pow2[100], dp[100][100], bit[100], n;
int dfs(int pos, int cnt, bool limit){
    if(!pos) return pow2[cnt];
    if(!limit && dp[pos][cnt]!=-1) return dp[pos][cnt];
    int up=limit?bit[pos]:1, res=0;
    for(int i=0;i<=up;i++)
        res=(res+dfs(pos-1,cnt+i,limit&&(i==up)))%mod;
    if(!limit) dp[pos][cnt]=res;
    return res;
}
int solve(unsigned long long x){
    int len=0;
    while(x){
        bit[++len]=x&1;
        x>>=1;}
    return dfs(len,0,true);
}
signed main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    memset(dp,-1,sizeof(dp)); pow2[0]=1;
    for(int i=1;i<100;i++) pow2[i]=(pow2[i-1]*2)%mod;
    cin>>n; int odd=solve(n-1);
    int total=((__int128)n%mod*(n+1)%mod*inv2)%mod;
    int even=(total-odd+mod)%mod;
    cout<<even<<"\n";
}

posted @ 2025-08-22 15:39  BaiBaiShaFeng  阅读(7)  评论(0)    收藏  举报
Sakana Widget右下角定位