HDU 2865 Birthday Toy(ploya好題)

對於這種顏色多的,但是限制簡單的情況,可以利用dp推出公式,然後矩陣快速冪求解

代碼:

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

const int MOD = 1000000007;
typedef long long ll;

int n, k;

int phi(int n) {
    int ans = n;
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) ans = ans / i * (i - 1);
        while (n % i == 0) n /= i;
    }
    if (n > 1) ans = ans / n * (n - 1);
    return ans;
}

struct Mat {
    int v[2][2];
    Mat() {memset(v, 0, sizeof(v));}
    Mat operator * (Mat c) {
        Mat ans;
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                for (int k = 0; k < 2; k++) {
                    ans.v[i][j] = (ans.v[i][j] + (ll)v[i][k] * c.v[k][j] % MOD) % MOD;
                }
            }
        }
        return ans;
    }
};

Mat pow_mod(Mat x, int k) {
    Mat ans;
    for (int i = 0; i < 2; i++) ans.v[i][i] = 1;
    while (k) {
        if (k&1) ans = ans * x;
        x = x * x;
        k >>= 1;
    }
    return ans;
}

int cal(int k, int n) {
    Mat A;
    A.v[0][0] = k - 2; A.v[0][1] = k - 1; A.v[1][0] = 1;
    if (n == 1) return 0;
    if (n == 2) return (ll)k * (k - 1) % MOD;
    A = pow_mod(A, n - 2);
    return (ll)(k - 1) * A.v[0][0] % MOD * k % MOD;
}

int pow_mod(int x, int k) {
    int ans = 1;
    while (k) {
        if (k&1) ans = (ll)ans * x % MOD;
        x = (ll)x * x % MOD;
        k >>= 1;
    }
    return ans;
}

int main() {
    while (~scanf("%d%d", &n, &k)) {
        int ans = 0;
        for (int i = 1; i * i <= n; i++) {
            if (n % i == 0) {
                ans = (ans + (ll)phi(n / i) * cal(k - 1, i) % MOD) % MOD;
                if (n / i != i) {
                    int tmp = n / i;
                    ans = (ans + (ll)phi(n / tmp) * cal(k - 1, tmp) % MOD) % MOD;
                }
            }
        }
        ans = (ll)ans * pow_mod(n, MOD - 2) % MOD * k % MOD;
        printf("%d\n", ans);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章