狄利克雷卷积 【HDU5628】Clarke and math

题目大意:
狄利克雷卷积 【HDU5628】Clarke and math
文章图片

给定f(1~n),求g(1~n)
【狄利克雷卷积 【HDU5628】Clarke and math】题目分析:(狄利克雷卷积)
狄利克雷卷积:
狄利克雷卷积 【HDU5628】Clarke and math
文章图片

狄利克雷卷积满足:交换律,结合律,分配率等性质(和乘法是一样的)。
我们设函数g(i)=1
如果k==1,则 i 的答案为: (f?g)(n)=∑d1|nf(d1)( f ? g ) ( n ) = ∑ d 1 | n f ( d 1 )
如果k==2,则 i 的答案为: ((f?g)?g)(n)=∑d1|n∑d2|d1f(d2)( ( f ? g ) ? g ) ( n ) = ∑ d 1 | n ∑ d 2 | d 1 f ( d 2 )
以此类推
则最终答案为 f?(gk)f ? ( g k )
所以只要求logk次狄利克雷卷积就可以了。
但是如果是枚举i,枚举i的约数,时间复杂度为n^2,明显接受不了。
所以我们直接枚举约数,然后枚举该约数和哪些数相乘。
这样时间复杂是nlogn的。
总时间复杂度O(nlognlogk)
代码如下:

#include #define N 120000 using namespace std; const int mod=1e9+7; int T,n,k; struct fun{ int a[N]; void make_f() { for(int i=1; i<=n; i++) scanf("%d",&a[i]); } void make_g() { for(int i=1; i<=n; i++) a[i]=1; } fun operator * (const fun &c) const { static fun z; for(int i=1; i<=n; i++) z.a[i]=0; for(int i=1; i*i<=n; i++) for(int j=i; j*i<=n; j++) { z.a[i*j]+=1ll*a[i]*c.a[j]%mod,z.a[i*j]%=mod; if(i!=j) z.a[i*j]+=1ll*a[j]*c.a[i]%mod,z.a[i*j]%=mod; } return z; } void print() { printf("%d",a[1]); for(int i=2; i<=n; i++) printf(" %d",a[i]); printf("\n"); } }; void Fast_Power(fun &ans,fun a,int k) { while(k) { if(k&1) ans=ans*a; a=a*a; k>>=1; } } int main() { scanf("%d",&T); while(T--) { scanf("%d%d",&n,&k); fun f,g; f.make_f(); g.make_g(); Fast_Power(f,g,k); f.print(); } return 0; }

    推荐阅读