P4317 花神的数论题 题解

话说好久没写题解了

image


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\) 位为 \(1\) 的位上后面那一堆数字里面挑出 \(j\) 个数的方案 \(num_i\) 就好了,注意加上 \(cnt\).那么结果显然为 \(\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();}

完结撒花~

image

posted @ 2024-06-21 10:47  DrRatio  阅读(46)  评论(2编辑  收藏  举报