hdu5628(狄利克雷卷积,快速幂)

Problem Description
Clarke is a patient with multiple personality disorder. One day, he turned into a mathematician, did a research on interesting things.
Suddenly he found a interesting formula. Given f(i),1≤i≤n, calculate
g(i)=∑i1∣i∑i2∣i1∑i3∣i2⋯∑ik∣ik−1f(ik) mod 1000000007(1≤i≤n)
Input
The first line contains an integer T(1≤T≤5), the number of test cases.
For each test case, the first line contains two integers n,k(1≤n,k≤100000).
The second line contains n integers, the ith integer denotes f(i),0≤f(i)<109+7.
Output
For each test case, print a line contained n integers, the ith integer represents g(i).
Sample Input
2
6 2
2 3 3 3 3 3
23 3
2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
Sample Output
2 7 7 15 7 23
2 9 9 24 9 39 9 50 24 39 9 102 9 39 39 90 9 102 9 102 39 39
Hint
In the first sample case:
f(1)=2,f(2)=f(3)=f(4)=f(5)=f(6)=3
when k=1
g(1)=f(1)=2,g(2)=f(1)+f(2)=5,g(3)=f(1)+f(3)=5,g(4)=f(1)+f(2)+f(4)=2+3+3=8,g(5)=f(1)+f(5)=5,g(6)=f(1)+f(2)+f(3)+f(6)=2+3+3+3=10
when k=2
g(1)=f(1)=2,g(2)=f(1)+(f(1)+f(2))=7,g(3)=f(1)+(f(1)+f(3))=7,g(4)=f(1)+(f(1)+f(2))+(f(1)+f(4))=15,g(5)=f(1)+(f(1)+f(5))=7,g(6)=f(1)+(f(1)+f(2))+(f(1)+f(3))+(f(1)+f(2)+f(3)+f(6))=23
Therefore output
2 7 7 15 7 23


s o l u t i o n solution solution:
我们知道做一次狄利克雷卷积相当于 f ∗ I f*I fI
∗ * 表示狄利克雷卷积

相当于要求 f ∗ I k f*I^k fIk
具有交换律故直接快速幂即可

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back 
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
int rd()
{
	int num = 0;char c = getchar();bool flag = true;
	while(c < '0'||c > '9') {if(c == '-') flag = false;c = getchar();}
	while(c >= '0' && c <= '9') num = num*10+c-48,c = getchar();
	if(flag) return num;else return -num;
}
const int p = 1e9+7;
int n,k;
int a[101000];
int f[101000],tmp[101000],now[101000];
inline int mul(int a,int b){return 1ll*a*b%p;}
inline int calc(int a,int b){return (a+=b)>=p?a-=p:a;}
void Mul(int *a,int *b)
{
	rep(i,1,n) tmp[i] = 0;
	rep(i,1,n)
		for(int j = i;j <= n;j += i)
			tmp[j] = calc(tmp[j],mul(a[i],b[j/i]));
    rep(i,1,n) a[i] = tmp[i];
}
void ksm(int *a,int x)
{
	rep(i,1,n) now[i] = 1;
	while(x)
	{
		if(x&1) Mul(f,now);
		Mul(now,now);
		x >>= 1;
	}
	
}
void init()
{
	n = rd();k = rd();
	rep(i,1,n) a[i] = rd();
	rep(i,1,n) f[i] = 1;
	ksm(f,k-1);
	Mul(a,f);
	rep(i,1,n-1) printf("%d ",a[i]);printf("%d\n",a[n]);
}
int main()
{
	int T = rd();
	while(T--) init();
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值