1. 程式人生 > 實用技巧 >HDU 6755 (數論綜合題,2020多校)

HDU 6755 (數論綜合題,2020多校)

題目:傳送門

題意

定義 Fn 為斐波那契第 n 項,遞推式為

輸入 N,C,K(1 <= N,C <= 1e18, 1 <= K <= 1e5), 求

輸出答案對 1e9 + 9 取模

思路

參考部落格

首先,需要知道斐波那契數列的通項公式

然後我們可以用二次剩餘,求出 sqrt(5) 在 mod 1e9 + 9 意義下的值,然後再對其求一下逆元,就得到 1 / sqrt(5) 在 mod 1e9 + 9 的值,這樣,(1 + sqrt(5)) / 2 和 (1 - sqrt(5)) / 2 在 mod 1e9 + 9 意義下的值都可以求得。

後面的都是二項式的展開,和一些優化,這題卡常,沒有優化的話會超時,具體的可以看參考部落格。

#include <bits/stdc++.h>
#define LL long long
#define ULL unsigned long long
#define UI unsigned int
#define mem(i, j) memset(i, j, sizeof(i))
#define rep(i, j, k) for(int i = j; i <= k; i++)
#define dep(i, j, k) for(int i = k; i >= j; i--)
#define pb push_back
#define make make_pair
#define
INF 0x3f3f3f3f #define inf LLONG_MAX #define PI acos(-1) #define fir first #define sec second #define lb(x) ((x) & (-(x))) #define dbg(x) cout<<#x<<" = "<<x<<endl; using namespace std; const int N = 1e6 + 5; const LL mod = 1e9 + 9; LL fac[N], ifac[N], n, c; int k; LL ksm(LL a, LL b) { a
%= mod; if(b > mod) b = b % (mod - 1) + mod - 1; LL res = 1LL; while(b) { if(b & 1) res = res * a % mod; a = a * a % mod; b >>= 1; } return res; } LL C(int n, int m) { return fac[n] * ifac[m] % mod * ifac[n - m] % mod; } void solve() { scanf("%lld %lld %d", &n, &c, &k); LL inv_SqrtFive = 276601605; LL A = ksm(691504013, c); LL B = ksm(308495997, c); LL an = ksm(A, k); LL bn = 1LL; LL ifac_A = ksm(A, mod - 2); LL ans = 0LL; rep(i, 0, k) { LL res = an * bn % mod, tmp; if(res == 1LL) tmp = n % mod; else tmp = res * (ksm(res, n) - 1LL) % mod * ksm(res - 1, mod - 2) % mod; tmp = tmp * C(k, i) % mod; if(i & 1) ans = (ans - tmp + mod) % mod; else ans = (ans + tmp) % mod; an = an * ifac_A % mod; bn = bn * B % mod; } ans = ans * ksm(inv_SqrtFive, k) % mod; printf("%lld\n", ans); } int main() { fac[0] = 1LL; for(int i = 1; i <= 100000; i++) fac[i] = 1LL * i * fac[i - 1]% mod; ifac[100000] = ksm(fac[100000], mod - 2); dep(i, 0, 99999) ifac[i] = 1LL * (i + 1LL) * ifac[i + 1] % mod; int _; scanf("%d", &_); while(_--) solve(); // solve(); return 0; }