花神的数论题(这题...哎。数位dp咋就这么 not naive 呢)

题意简介

没什么好说,就是让你求出 1 ~ n 之间每个数转化为二进制后 '1' 的个数,然后乘起来输出积

题目分析

emmmm.... 两种解法(同是 $O(\log^2 N)$ 的算法,组合数效率完爆 数位dp,当然是我自己的数位dp)。

  1. 组合数直接艹。(数据范围8e9 能过,其实这个东西你搞一搞 __int128 什么的再找个大质数也许也能过去啦)(好吧这个直接暴力预处理组合数的数组就好了)
  2. 老老实实数位dp。(可以AC)

于是翻车了...这么久

算法实现

1. 组合数 

组合数非常好做,只需要想想第 i 位为 1 的位上后面那一堆数字里面挑出 j 个数的方案就好了,注意加上 cnt ,然后最后快速幂累加一下答案,分分钟搞定

然后这里用了逆元处理组合数要预处理的阶乘,如果你还不会线性求逆元的话可以点这里

当然这里用逆元...就是作死...我们完全可以预处理出 50 * 50 的杨辉三角数组,存好组合数直接用

2.数位dp

...不就是枚举 1 的个数然后记忆化深搜么?hem...听起来完全没有组合数高级

代码实现

1.组合数

 //by Judge
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
const int M=;
const ll mod=1e7+;
ll n,len,cnt,ans=;
ll C[M][M],d[M],num[M];
inline void prep(){ //预处理组合数模板?
for(int i=;i<=;++i) C[i][]=;
for(int i=,j;i<=;++i) for(j=;j<=;++j)
C[i][j]=C[i-][j]+C[i-][j-];
}
inline ll quick_pow(ll x,ll p,ll ans=){ //快速幂模板?
while(p){
if(p&) ans=ans*x%mod;
x=x*x%mod, p>>=;
} return ans;
}
signed main(){
cin>>n,prep();
while(n) d[++len]=n&,n>>=;//转化二进制
for(ll i=len,j;i;--i) if(d[i]){
for(j=;j<i;++j) //组合数就是随便乱艹的算法
num[cnt+j]+=C[i-][j];
++num[++cnt];
}
for(ll i=;i<=len;++i) //直接累乘就好
ans=ans*quick_pow(i,num[i])%mod;
cout<<ans<<endl; return ;
}

2.数位dp

 //by Judge
#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
using namespace std;
const int M=;
const int mod=1e7+;
int cnt,x[M];
ll n,f[M][][M][M],num[M];
inline ll quick_pow(ll x,ll p,ll ans=){
while(p) (p&) && (ans=ans*x%mod),x=x*x%mod, p>>=;
return ans;
}
ll dp(int cur,int up,int tmp,int d){ //记忆化深搜,log^2 n 无压力
if(!cur) return tmp==d; //特判直接返回
if(~f[cur][up][tmp][d]) return f[cur][up][tmp][d]; // 已记忆,直接返回
int lim=up?x[cur]:;
ll res=;
for(int i=;i<=lim;++i) //继续深搜
res+=dp(cur-,up&&i==lim,tmp+(i==),d);
return f[cur][up][tmp][d]=res; //记忆化
}
ll solv(){
while(n) x[++cnt]=n&,n>>=; //同上转化
for(int i=;i<=;++i) //枚举要放入的 1 的位数
memset(f,-,sizeof(f)),
num[i]=dp(cnt,,,i);
ll res=;
for(int i=;i<=;++i) //累乘进答案
res=res*quick_pow(i,num[i])%mod;
return res;
}
signed main(){ cin>>n,cout<<solv()<<endl; return ; }
上一篇:Javascript中JSON的序列化和反序列化(转)


下一篇:自动化测试selenium+java 第一章