http://codeforces.com/gym/101161/attachments
这题通过打表,可以知道长度是i的时候的合法方案数。
然后得到f[1] = 2, f[2] = 3, f[3] = 5, f[4] = 8......这样的广义fib数列
现在要求f[k] + f[2k] + f[3k] + ...... + f[xk]的总和。
直接做很难做,我不知道f[i * k] = x * f[(i - 1) * k] + y * f[(i - 2) * k]
推不出系数的话,有一个结论就是:fib的任意一项肯定能表示成x * f(i - 1) + y * f(i - 2),就是两个连续的fib数字,能表示出后面所有的fib数列。知道这样的东西后。
可以知道,比如k = 2
形如f(6) = 2 * f(4) + f(3)、然后f(8) = 2 * f(6) + f(5)
那么就可以构造矩阵了。
sum, f(4),f(3) -----> newSum, f(6), f(5)
同样用f(4)和f(3)把f(5)表示出来即可(注意:肯定能表示)
一般构造了矩阵后,写一个求第k项的函数出来,往往比较有用
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <string> #include <stack> #include <map> #include <set> #include <bitset> #define X first #define Y second #define lson T[rt].l #define rson T[rt].r #define clr(u,v); memset(u,v,sizeof(u)); #define in() freopen("data.txt","r",stdin); #define out() freopen("ans","w",stdout); #define Clear(Q); while (!Q.empty()) Q.pop(); #define pb push_back using namespace std; typedef long long LL; typedef pair<int, int> pii; const int maxn = 5; const int MOD = 1e9 + 7; struct Matrix { LL a[maxn][maxn]; int row, col; } base, a; struct Matrix mul(struct Matrix a, struct Matrix b, int MOD) { struct Matrix c = {0}; c.row = a.row, c.col = b.col; for (int i = 1; i <= a.row; ++i) { for (int j = 1; j <= b.col; j++) { for (int k = 1; k <= b.row; ++k) { c.a[i][j] += a.a[i][k] * b.a[k][j]; c.a[i][j] %= MOD; } } } return c; } struct Matrix qp(Matrix ans, Matrix base, LL n, LL MOD) { while (n) { if (n & 1) { ans = mul(ans, base, MOD); } n >>= 1; base = mul(base, base, MOD); } return ans; } int f; void initBaseFib() { base.row = base.col = 2; base.a[1][1] = 1, base.a[1][2] = 1; base.a[2][1] = 1, base.a[2][2] = 0; } LL findK(int a, int b, LL k) { if (k == 1) return a; if (k == 2) return b; initBaseFib(); Matrix t; t.row = 1, t.col = 2; t.a[1][1] = b, t.a[1][2] = a; t = qp(t, base, k - 2, MOD); return t.a[1][1]; } void initBaseSum(int a, int b, int c, int d) { base.row = base.col = 3; base.a[1][1] = 1, base.a[1][2] = 0, base.a[1][3] = 0; base.a[2][1] = 1, base.a[2][2] = a, base.a[2][3] = b; base.a[3][1] = 0, base.a[3][2] = c, base.a[3][3] = d; } int pre[22]; int sum[22]; LL getpos(LL n, LL k) { if (n == 0) return 0; if (n == 1) return findK(2, 3, n * k); if (k == 2) { initBaseSum(2, 1, 1, 1); Matrix t; t.row = 1, t.col = 3; t.a[1][1] = 3, t.a[1][2] = 8, t.a[1][3] = 5; t = qp(t, base, n - 1, MOD); return t.a[1][1]; } else if (k == 3) { initBaseSum(3, 2, 2, 1); Matrix t; t.row = 1, t.col = 3; t.a[1][1] = 5, t.a[1][2] = 21, t.a[1][3] = 13; t = qp(t, base, n - 1, MOD); return t.a[1][1]; } else { Matrix t; t.row = 1, t.col = 3; t.a[1][1] = findK(2, 3, k), t.a[1][2] = findK(2, 3, 2 * k), t.a[1][3] = findK(2, 3, 2 * k - 1); initBaseSum(findK(2,3,k-1), findK(2,3,k-2), findK(2,3,k-2), findK(2,3,k-3)); t = qp(t, base, n - 1, MOD); return t.a[1][1]; } } void work() { LL be, en, k; cin >> be >> en >> k; if (k == 1) { //sumofall fib if (en <= 2) { printf("Case %d: %d ", ++f, sum[en] - sum[be - 1]); return; } initBaseSum(1, 1, 1, 0); be--; a.row = 1, a.col = 3; a.a[1][1] = 2, a.a[1][2] = 3, a.a[1][3] = 2; Matrix ret = qp(a, base, en - 1, MOD); LL resEn = ret.a[1][1]; LL resBe = 0; if (be - 1 >= 0) { ret = qp(a, base, be - 1, MOD); resBe = ret.a[1][1]; } printf("Case %d: %d ", ++f, (resEn - resBe + MOD) % MOD); return; } else { en = en / k; if (be % k == 0) be = (be - k) / k; else be /= k; // cout << be << " " << en << endl; LL ans = (getpos(en, k) - getpos(be, k) + MOD) % MOD; printf("Case %d: %d ", ++f, ans); } } int cnt[22]; void dfs(int k, int t1, int t2) { if (k == t1 || k == t2) { cnt[k]++; return; } dfs(k - 1, t1, t2); dfs(k - 2, t1, t2); } int main() { #ifdef local in(); #else #endif pre[1] = 2, pre[2] = 3, pre[3] = 5, pre[4] = 8; sum[1] = 2, sum[2] = 5, sum[3] = 10, sum[4] = 18; // int one = 6, t1 = 4, t2 = 2; // dfs(one, t1, t2); // cout << cnt[t1] << " " << cnt[t2] << endl; int t; scanf("%d", &t); while (t--) work(); return 0; }