hdu5628 Clarke and math

Posted henry-1202

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 modspace 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
", g[n]);
    }
}

以上是关于hdu5628 Clarke and math的主要内容,如果未能解决你的问题,请参考以下文章

HDU - 5628:Clarke and math (组合数&线性筛||迪利克雷卷积)

hdu 5625 Clarke and chemistry

HDU 5627Clarke and MST

hdu 5626 Clarke and points

HDU 5464 Clarke and problem 动态规划

51Nod 1769Clarke and math2