牛客练习赛84 F 牛客推荐系统开发之下班

牛客推荐系统开发之下班

https://ac.nowcoder.com/acm/contest/11174/F

好像只有我的公式是长这样的,但是跑的最快。
考虑到
其中,*是狄利克雷卷积,I是单位1。
进行杜教筛即可。
这里提一点,一个函数和mu卷是可以O(n)的求的。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;

typedef long long ll;

const int N = 5e6 + 100;
const int M = N - 100;
const int MOD = 1e9 + 9;

int tot;
int pri[N], f[N];
bool is_prime[N];

void upd(int &a, int b) {
    a += b; if (a >= MOD) a -= MOD;
}

void get_phi() {
    memset(is_prime, true, sizeof(is_prime));
    for (int i = 2; i < N; i++) {
        if (is_prime[i]) pri[tot++] = i;
        for (int j = 0; j < tot && i * pri[j] < N; j++) {
            is_prime[i * pri[j]] = false;
            if (i % pri[j] == 0) break;
        }
    }
    f[1] = 1;
    for (int i = 2; i <= M; i++) {
        f[i] = f[i - 1] + f[i - 2]; 
        if (f[i] >= MOD) f[i] -= MOD;
    }
    for (int i = 0; i < tot; i++) {
        for (int j = M / pri[i]; j; j--) {
            upd(f[j * pri[i]], MOD - f[j]);
        }
    }
    for (int i = 1; i <= M; i++) upd(f[i], f[i - 1]);
}

map<int, int> sf;

int fu[5][5], co[5][5], res[5][5];

void cal(int a[][5], int b[][5]) {
    for (int i = 0; i < 2; i++)
        for (int j = 0; j < 2; j++)
            for (int k = 0; k < 2; k++)
                fu[i][j] = (fu[i][j] + 1LL * a[i][k] * b[k][j]) % MOD;
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 2; j++) {
            a[i][j] = fu[i][j];
            fu[i][j] = 0;
        }
    }
}

ll get(ll n) {
    n--;
    res[0][1] = res[1][0] = co[1][1] = 0;
    res[0][0] = res[1][1] = co[0][0] = co[0][1] = co[1][0] = 1;
    while (n > 0) {
        if (n & 1) cal(res, co);
        cal(co, co); n /= 2;
    }
    return res[0][0];
}

ll F(ll n) {
    if (n <= M) return f[n];
    if (sf.count(n)) return sf[n];
    int ans = get(n + 2) - 1;
    for (int l = 2, r; l <= n; l = r + 1) {
        r = n / (n / l);
        ans = (ans - (r - l + 1LL) * F(n / l)) % MOD;
    }
    ans = (ans % MOD + MOD) % MOD;
    return sf[n] = ans;
}

ll qpow(ll x, ll n) {
    ll res = 1;
    while (n > 0) {
        if (n & 1) res = res * x % MOD;
        x = x * x % MOD;
        n /= 2;
    }
    return res;
}

int n, k;
int a, b = 1;

int main() {
    //freopen("0.txt", "r", stdin);
    get_phi(); 
    scanf("%d%d", &n, &k);
    ll ans = 0;
    for (int l = 1, r; l <= n; l = r + 1) {
        r = n / (n / l);
        ll co = qpow(n / l, k);
        ans = (ans + co * (F(r) - F(l - 1))) % MOD;
    }
    ans = (ans % MOD + MOD) % MOD;
    printf("%lld\n", ans);
    return 0;
}
全部评论

相关推荐

AaronRuan:看到了好多开奖了,不知道为啥自己也有点激动,真的替你们感到高兴啊
点赞 评论 收藏
分享
评论
3
收藏
分享
牛客网
牛客企业服务