【51Nod1769】Clarke and math2(数论,组合数学)

【51Nod1769】Clarke and math2(数论,组合数学)

题面

51Nod

题解

考虑枚举一个\(i_k\),枚举一个\(i\),怎么计算\(i_k\)\(i\)的贡献。
\(\frac{i}{i_k}\)拆掉,维护一个长度为\(k\)的数组,表示\(\frac{i_{k-1}}{i_{k}}\),对于每一个质因子,假设其出现次数为\(a\),那么就是把\(a\)个元素放进\(k\)个盒子里,盒子可以空,这个的方案数是\({a+k-1\choose k-1}={a+k-1\choose a}\),不难发现\(a\)很小,所以可以直接\(O(a)\)暴力算。
于是我们提前对于每一个\(a\)算出方案数,然后提前把质因数分解好,就可以做到\(O(nlogn)\)了。

#include<iostream>
#include<cstdio>
using namespace std;
#define MOD 1000000007
#define MAX 500500
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=(x*10ll+ch-48)%MOD,ch=getchar();
	return t?-x:x;
}
int n,K,C[25],f[MAX],g[MAX],x[MAX],v[MAX],inv[25];
int main()
{
	n=read();K=read();
	for(int i=1;i<=n;++i)f[i]=read();
	inv[0]=inv[1]=1;for(int i=2;i<=20;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
	for(int i=1;i<=20;++i)inv[i]=1ll*inv[i-1]*inv[i]%MOD;
	for(int a=0;a<=20;++a)
	{
		int nw=(a+K-1)%MOD;C[a]=inv[a];
		for(int i=0;i<a;++i)C[a]=1ll*C[a]*(nw-i+MOD)%MOD;
	}
	for(int i=1;i<=n;++i)x[i]=i,v[i]=1;
	for(int i=2;i<=n;++i)
		if(x[i]!=1)
			for(int j=i;j<=n;j+=i)
			{
				int a=0;
				while(x[j]%i==0)++a,x[j]/=i;
				v[j]=1ll*v[j]*C[a]%MOD;
			}
	for(int i=1;i<=n;++i)
		for(int j=i;j<=n;j+=i)
			g[j]=(g[j]+1ll*f[i]*v[j/i])%MOD;
	for(int i=1;i<=n;++i)printf("%d ",g[i]);
	puts("");return 0;
}
posted @ 2019-07-05 16:53  小蒟蒻yyb  阅读(317)  评论(0编辑  收藏  举报