HDU 4565【二阶递推】

来源:互联网 发布:淘宝网logo图片 编辑:程序博客网 时间:2024/06/05 11:58

大神安利的 http://wenku.baidu.com/link?url=TQqH0Eu6SbOBNLPwIm0mECspaTw9qZ46dtGfjTepX9y_4YdR6NmtZdfSq_nFtOcaYR3_cG8WjwDqeStvgn6fUGzKKspicPOMAw-MNg15scG&qq-pf-to=pcqq.c2c

题目大意:求 (a+b)nmodm,其中有 (a1)2<b<a2

怎么感觉和 JLOI2015 的那道题差不多QAQ

由条件得 0<ab<1
先看 (a+b)n+(ab)n
展开一下就知道它一定是个整数嘛
所以原式 Sn=(a+b)n+(ab)nmodm
然后就可以得到递推式

Sn=2aSn1+(ba2)Fn2

矩乘,没了…QAQ

#include<iostream>#include<cstdio>#include<cstdlib>#include<algorithm>#include<ctime>#include<cmath>#include<string>#include<cstring>#define LL long longusing namespace std;LL n,m,a,b;LL A[2][2],t[2][2],ret[2][2];void mul(LL A[][2],LL B[][2]){    for (int i = 0;i < 2;i ++)        for (int j = 0;j < 2;j ++)        {            t[i][j] = 0;            for (int k = 0;k < 2;k ++)                (t[i][j] += A[i][k] * B[k][j]) %= m;        }    for (int i = 0;i < 2;i ++)        for (int j = 0;j < 2;j ++)            A[i][j] = t[i][j];}void ksm(int B){    ret[0][0] = ret[1][1] = A[1][0] = 1;    ret[0][1] = ret[1][0] = A[1][1] = 0;    A[0][0] = a * 2,A[0][1] = b - a * a;    for (;B;B >>= 1,mul(A,A))        if (B & 1) mul(ret,A);}LL F(int n){    int s = sqrt(b),t = (s * s != b);    if (n == 1) return (a + s + t) % m;        else return (a * a + b + (int)(sqrt(b) * a * 2) + t) % m;}int main(){    while (~scanf("%lld%lld%lld%lld",&a,&b,&n,&m))    {        if (n == 1)        {            cout << F(1) << endl;            continue;        }        ksm(n - 2);        cout << ((ret[0][0] * F(2) + ret[0][1] * F(1)) % m + m) % m << endl;    }    return 0;}
0 0