hdu 5628 Clarke and math Dirichlet卷积

来源:互联网 发布:百度网络存在安全隐患 编辑:程序博客网 时间:2024/06/15 03:32

设f,g为两个数论函数,那么规定 (f∗g)(n)=∑d|n f(d)g(n/d)为f,g的Dirichlet卷积

该运算满足 交换律、结合律、分配律。

并且存在一个幺元e,使得e*f = f。   当i = 1 时 e[i] = 1,i != 1 时 e[i] = 0;


另函数 h[i]  恒等于 1.

g(i)=i1ii2i1i3i2ikik1f(ik)   =  i1ii2i1i3i2ikik1f(ik) *h(ik) .

化为Dirichlet卷积形式,g(i) =  (f*h^k)(i)

由于满足交换律, 先利用快速幂h^k。最后再拿h^k的结果与f卷积(注意,两个函数卷积的结果是函数,而不是值)

每次Dirichlet卷积的 复杂度为 O(n*logn),进行logk次卷积计算,单组复杂度O(n*logn*logk).

/************************************************************************* > File Name: hdu5628.cpp > Author: TechMonster > Mail: 928221136@qq.com > Created Time: 三  7/13 16:20:40 2016 ************************************************************************/#include<stdio.h>#include<string.h>#include<math.h>#include<algorithm>using namespace std;#define MS(x,y) memset(x,y,sizeof(x))typedef long long LL;const int N = 100010;const LL M = 1e9+7;template <class T1, class T2>inline void gadd(T1 &a, T2 b) {a += b;if(a > M) a%= M;}int n,k;LL f[N],ans[N],tem[N],x[N];void Dirichlet(LL *ans, LL *x)//Dirichlet卷积{MS(tem,0);for(int i = 1; i*i <= n; ++i){gadd(tem[i*i],ans[i]*x[i]%M);for(int j = i+1; j*i <= n; ++j){gadd(tem[i*j],ans[i]*x[j]%M);gadd(tem[i*j],ans[j]*x[i]%M);}}for(int i = 1; i <= n; ++i) ans[i] = tem[i];}void calc(){while(k) //快速幂{if(k&1) Dirichlet(ans,x);Dirichlet(x,x);k>>=1;}Dirichlet(ans,f); //乘f}void solve(){scanf("%d%d",&n,&k);for(int i = 1; i <= n; ++i){scanf("%lld",&f[i]);ans[i] = 0; x[i] = 1;//初始ans为幺元,x为恒等于1的函数}ans[1] = 1;calc();for(int i = 1; i < n; ++i) printf("%lld ",ans[i]);printf("%lld\n",ans[n]);}int main(){int T;scanf("%d",&T);while(T--)solve();return 0;}



2 0
原创粉丝点击