头
话说好久没写题解了
P4317 花神的数论题
题意:给你一个不超过 \(10^{15}\) 的数 \(n\),求 \(\prod_{i=1}^n sum_i\),其中 \(sum_i\) 表示 \(i\) 在二进制表示下 \(1\) 的个数。
学了几道题后,本能的设出了 \(f_{i,j}\) 表示 \(i\) 位数中含 \(j\) 个 \(1\) 的数的个数,转移方程为:
\[f_{i,j}=f_{i-1,j}+f_{i-1,j-1} \]那么之后呢?
如果你仔细研究过上面的转移,你也许会发现,它就相当于组合数 C 的预处理。
组合数又有什么特殊性质呢?
别急,我们先用暴力的代码打表找找规律。
得到:
1 1
2 1
3 2
4 1
5 2
6 2
7 3
换一种形式并加以排序,得到:
1
1 2
1 2 2 3
1 2 2 2 3 3 3 4
记录每行每个数的个数,则有:
1
1 1
1 2 1
1 3 3 1
杨辉三角!
现在我们是否能想起来,杨辉三角除去第一列后的数值等于对应的组合数。
之后,我们只要求出 \(n\) 在二进制意义下的位数 \(len\) 及每一位 \(i\) 在 \(0\) 和 \(1\) 的状态下的总数 \(num_i\),那么结果显然为 \(\prod_{i=1}^{len} i^{sum_i}\)。
其他的,注意 \(mod\) 和 long long
。
code:
const int mod=1e7+7;
ll n,cnt,len,ans=1;
ll f[51][51],d[51],num[51];
namespace Wisadel
{
void Wpre()
{
fo(i,0,50) f[i][0]=1;
fo(i,1,50)
{
fo(j,1,i)
f[i][j]=f[i-1][j]+f[i-1][j-1];
}
}
ll Wqp(ll x,ll y)
{
ll res=1;
while(y)
{
if(y&1)
res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res;
}
short main()
{
Wpre();
n=qr;
while(n)
d[++len]=n&1,n>>=1;
fu(i,len,1)
if(d[i])
{
fo(j,1,i-1)
num[cnt+j]+=f[i-1][j];
++num[++cnt];
}
fo(i,1,len)
ans=ans*Wqp(i,num[i])%mod;
printf("%lld\n",ans);
return Ratio;
}
}
int main(){return Wisadel::main();}