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";
}

浙公网安备 33010602011771号