浏览器标题切换
浏览器标题切换end
把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

hdu5628 Clarke and math

题目地址

题目链接

题意

\[g(i)=\sum_{i1|i}\sum_{i_2|i_1}\sum_{i_3|i_2}...\sum_{i_k|i_{k-1}}f(i_k)\space mod\space 10^9+7 \]

题解

考虑当\(k=1\)时怎么做

\[g(i)=\sum_{i_1|i}f(i_1) \]

显然可以\(O(\sqrt{n})\)

我们尝试着把它表示成狄利克雷卷积的形式

\[g=f*I \]

考虑当\(k=2\)时是什么样子的

\[g(i)=\sum_{i_1|i}\sum_{i_2|i}f(i_2) \]

表示成狄利克雷卷积形式即为

\[g=(f*I)*I=f*I^2 \]

同理可得当k为任意值时

\[g=f*I^k \]

那么只需要快速幂一下就好,复杂度是\(O(nlognlogk)\)

注意不能枚举单个数的约数,时间复杂度会爆炸,我们可以枚举约数,并计算它对1~n中的数的贡献,这样复杂度是\(O(nlogn)\)的,所以总的复杂度是\(O(nlognlogk)\)

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int N = 1e5 + 10;
const int mod = 1e9 + 7;

int n, k;
int tmp[N], I[N], g[N];

void mul(int *a, int *b) {
	for(int i = 1; i <= n; ++i) tmp[i] = 0;
	for(int i = 1; i <= n; ++i) {
		for(int j = 1; i * j <= n; ++j) {
			tmp[i * j] = 1ll * (tmp[i * j] + 1ll * a[i] * b[j]) % mod;
		}
	}
	for(int i = 1; i <= n; ++i) a[i] = tmp[i];
}

int main() {
	int T; scanf("%d", &T);
	while(T--) {
		scanf("%d%d", &n, &k);
		for(int i = 1; i <= n; ++i) scanf("%d", &g[i]), I[i] = 1;
		while(k) { if(k & 1) mul(g, I); mul(I, I); k >>= 1; }
		for(int i = 1; i < n; ++i) printf("%d ", g[i]); printf("%d\n", g[n]);
	}
}
posted @ 2019-01-26 12:59  henry_y  阅读(199)  评论(0编辑  收藏  举报