zzuli 2180 GJJ的日常之沉迷数学【矩阵快速幂 || 逆元】

来源:互联网 发布:淘宝流量来源怎么获取? 编辑:程序博客网 时间:2024/05/20 15:59

Description

GJJ每天都要膜拜一发数学大佬,因为GJJ的数学太差了。这不,GJJ又遇到难题了,他想求助WJJ,但是WJJ这几天忙于追妹子,哪有时间给他讲题, 于是GJJ求助于热爱ACM的你,Acmer们能帮帮他吗?问题是求: k^0 + k^1 +…+ k^(n) mod p (0 < k < 100, 0 <= n <= 10^9, p = 1000000007)
例如:6^0 + 6^1 +…+ 6^(10) mod 1000000007 (其中k = 6, n = 10, p = 1000000007)
Input

输入测试数据有多组,每组输入两个整数k, n
Output

每组测试数据输出:Case #: 计算结果
Sample Input

2 1
6 10
Sample Output

Case 1: 3
Case 2: 72559411
思路:
我是构造矩阵快速幂写出来的,题解用的逆元+快速幂;
一个2 * 2矩阵,左上部分是K,右上和右下是1,左下是0的一个初始矩阵,只要求初始矩阵n+1次幂后,右上部分就是答案(0秒过题);

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;typedef long long LL;const LL mod = 1e9 + 7;LL n, m;struct mat{    LL mapp[2][2];};mat mat_mul(mat A, mat B) {    mat C;    memset(C.mapp, 0, sizeof(C.mapp));    for(int i = 0; i < 2; i++) {        for(int j = 0; j < 2; j++) {            for(int k = 0; k < 2; k++) {                C.mapp[i][k] = (C.mapp[i][k] + (A.mapp[i][j] % mod) * (B.mapp[j][k] % mod)) % mod;            }        }    }    return C;}LL mat_pow(mat A) {    mat ans;    ans.mapp[0][0] = ans.mapp[1][1] = 1;    ans.mapp[1][0] = ans.mapp[0][1] = 0;    while(n) {        if(n & 1) ans = mat_mul(ans, A);        A = mat_mul(A, A);        n >>= 1;    }    return ans.mapp[0][1];}int main() {    int p = 1;    while(scanf("%lld %lld", &m, &n) != EOF) {        n++;        mat base;        base.mapp[0][0] = m; //构造初始矩阵         base.mapp[0][1] = base.mapp[1][1] = 1;        base.mapp[1][0] = 0;        printf("Case %d: %lld\n",p++ ,mat_pow(base) % mod);    }    return 0;}

逆元+快速幂:(详解)
分析:等比数列的前n项和公式:s = (q^n - 1) / (q - 1),现在求前n + 1项,由于数比较大对mod = 1e9 + 7取模,同余定理不适用除法,这个时候就需要求逆元,费马小定理+快速幂或者扩展欧几里得都可以(这里用的是费马小定理:a,p互质,则 a^(p - 1) % p = 1)。
设 A = q - 1,因为(A,mod) = 1(表示互质),A^(mod - 1) % mod = 1 ,所以,s = (q^n - 1) / (q - 1) = [ (q^n - 1) / (q - 1) ] * [ (q - 1)^(mod - 1) % mod] % mod = s = (q^n - 1) * (q - 1)^(mod - 2) % mod,这样用快速幂正常写就行了,特判一下1。

#include<bits/stdc++.h>using namespace std;typedef long long LL;const LL mod = 1000000007;LL q_mod(LL a, LL b) {    LL ans = 1;    while(b) {        if(b&1) ans = ans * a % mod;        a = a * a % mod;        b >>= 1;    }    return ans;}int main(){//    freopen("in.txt", "r", stdin);//    freopen("o.txt", "w", stdout);    LL a, b, x, n, k, cnt = 0;    while(~scanf("%lld %lld", &k, &n)) {        if(k == 1) {            printf("Case %lld: %lld\n", ++cnt, n + 1);            continue;        }        a = q_mod(k, n + 1) - 1;        b = k - 1;        x = q_mod(b, mod - 2);        printf("Case %lld: %lld\n", ++cnt, a * x % mod);    }    return 0;}
原创粉丝点击