[NOI2011] 兔农 矩阵乘法,矩阵的等比数列求和

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
ll n,p;
ll k;
#define N 4000000
ll a[N],fr[N];
struct sq{
    ll a[3][3];
    sq(){memset(a,0,sizeof(a));}
    sq operator*(sq x)const{
           sq ans;
           for(ll i=1;i<=2;i++)for(ll j=1;j<=2;j++)for(ll z=1;z<=2;z++)(ans.a[i][j]+=a[i][z]*x.a[z][j])%=p;
           return ans;
    }
    void out(){
        for(ll i=1;i<=2;i++){
            for(ll j=1;j<=2;j++){
                cout<<a[i][j]<<" ";
            }
            cout<<endl;
        }
        cout<<endl;
    }
}tt;
ll hash[N];
struct sq2{
    ll a[5][5];
    sq2(){memset(a,0,sizeof(a));}
    sq2 operator*(sq2 x){
        sq2 ans;
        for(ll i=1;i<=4;i++)for(ll j=1;j<=4;j++)for(ll z=1;z<=4;z++)(ans.a[i][j]+=a[i][z]*x.a[z][j])%=p;
        return ans;
    }
    void out(){
        for(ll i=1;i<=4;i++){
            for(ll j=1;j<=4;j++){
                cout<<a[i][j]<<" ";
            }
            cout<<endl;
        }
        cout<<endl;
    }
};
sq ff(sq x,ll y){
    sq ans,k=x;
    for(ll i=1;i<=2;i++)ans.a[i][i]=1;
    for(ll i=0;(1LL<<i)<=y;i++){
        if((1LL<<i)&y)ans=ans*k;
        k=k*k;
    }
    return ans;
}
sq cheng(sq x,ll y){
    sq2 tr,ans1;
    for(ll i=1;i<=2;i++)for(ll j=1;j<=2;j++)ans1.a[i][j]=x.a[i][j];
    for(ll i=1;i<=2;i++){
        for(ll j=1;j<=2;j++){
           tr.a[i][j]=x.a[i][j];
        }
        tr.a[i][i+2]=1;
        tr.a[i+2][i+2]=1;
        ans1.a[i][i+2]=1;
    }
    for(ll i=0;(1LL<<i)<=y;i++){
        if(y&(1LL<<i)){
            ans1=ans1*tr;
        }
        tr=tr*tr;
    }
    sq kk;
    for(ll i=1;i<=2;i++)for(ll j=1;j<=2;j++){
        kk.a[i][j]=ans1.a[i][j+2];
    }
    return kk;
}
ll gcd(ll &p,ll &q,ll x,ll y){
    if(x==0){
        p=1,q=1;
        return y;
    }
    ll r=gcd(q,p,y%x,x);
    p-=q*(y/x);
    return r;
}
ll gcd(ll x,ll y){
    return x==0?y:gcd(y%x,x);
}
ll bn;
ll bb[N],cir;
ll ben[N];
ll res;
ll ni(ll x){
    ll p,q;
    if(gcd(x,k)!=1)return 0;
    gcd(p,q,x,k);
    return (p%k+k)%k;
}
int main(){
    tt.a[1][1]=1;
    tt.a[2][1]=1;
    tt.a[1][2]=1;
    sq u;
    u.a[1][1]=1;
    a[1]=1;a[2]=1;
    scanf("%lld%lld%lld",&n,&k,&p);
    for(ll i=3;i<=k*3;i++){
        a[i]=(a[i-1]+a[i-2])%k;
        if(!fr[a[i]])fr[a[i]]=i;
    }
    ll i=0;
    ll j=1;
    cir=n+1;
    ll ss=0;
    for(;;){
        ll u=ni(j);
        if(!u||!fr[u])break;
        ll g=a[fr[u]-1]*j%k;
        if(i+fr[u]>n)break;
        if(!ben[g]){
            ben[g]=1;
            bb[++bn]=i+fr[u];
            hash[g]=bn;
        }else{
            bb[++bn]=i+fr[u];
            ss=hash[g];
            cir=bb[bn]-bb[ss];
            break;
        }
        i=i+fr[u];
        j=g;
    }
    sq yy=ff(tt,cir);
    res=(u*ff(tt,n)).a[1][2];
    for(ll i=1;i<=bn;i++){
        if(i<=ss){
            (res-=(u*ff(tt,n-bb[i])).a[1][1])%=p;
        }else{ll uu=(n-bb[i])%cir;
        (res-=((u*(ff(tt,uu)*cheng(yy,(n-bb[i])/cir)))).a[1][1])%=p;
    }}
    res=(res%p+p)%p;
    cout<<res;
}

[NOI2011] 兔农 矩阵乘法,矩阵的等比数列求和

时间: 2024-10-07 05:35:26

[NOI2011] 兔农 矩阵乘法,矩阵的等比数列求和的相关文章

[BZOJ2432][Noi2011]兔农 矩阵乘法+exgcd

2432: [Noi2011]兔农 Time Limit: 10 Sec  Memory Limit: 256 MB Description 农夫栋栋近年收入不景气,正在他发愁如何能多赚点钱时,他听到隔壁的小朋友在讨论兔子繁殖的问题.问题是这样的:第一个月初有一对刚出生的小兔子,经过两个月长大后,这对兔子从第三个月开始,每个月初生一对小兔子.新出生的小兔子生长两个月后又能每个月生出一对小兔子.问第n个月有多少只兔子?聪明的你可能已经发现,第n个月的兔子数正好是第n个Fibonacci(斐波那契)

2432: [Noi2011]兔农 - BZOJ

Description 农夫栋栋近年收入不景气,正在他发愁如何能多赚点钱时,他听到隔壁的小朋友在讨论兔子繁殖的问题. 问题是这样的:第一个月初有一对刚出生的小兔子,经过两个月长大后,这对兔子从第三个月开始,每个月初生一对小兔子.新出生的小兔子生长两个月后又能每个月生出一对小兔子.问第n个月有多少只兔子? 聪明的你可能已经发现,第n个月的兔子数正好是第n个Fibonacci(斐波那契)数.栋栋不懂什么是Fibonacci数,但他也发现了规律:第i+2个月的兔子数等于第i个月的兔子数加上第i+1个月

HDU 4965 Fast Matrix Caculation ( 矩阵乘法 + 矩阵快速幂 + 矩阵乘法的结合律 )

HDU 4965 Fast Matrix Calculation ( 矩阵乘法 + 矩阵快速幂 + 矩阵乘法的结合律 ) #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define MAX_SIZE 1001 #define CLR( a, b ) memset( a, b, sizeof(a) ) #define MOD 6 typedef long lo

矩阵乘法&amp;&amp;矩阵快速幂&amp;&amp;最基本的矩阵模型——斐波那契数列

矩阵,一个神奇又令人崩溃的东西,常常用来优化序列递推 在百度百科中,矩阵的定义: 在数学中,矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合 ,最早来自于方程组的系数及常数所构成的方阵.这一概念由19世纪英国数学家凯利首先提出. 好,很高深对吧.那我们就更加直接地理解一下矩阵的实质:二维数组 好了这个SB都会,就不解释了 同二维数组一样,矩阵是一个'纵横排列的二维数据表格',它一般是一个n*m的二维数组,其中n*m表示它有n行m列 每一位上的数可以用下标i,j来表示,形如这样一个矩阵:

【BZOJ 2432】 [Noi2011]兔农 矩乘+数论

这道题的暴力分还是很良心嘛~~~~~ 直接刚的话我发现本蒟蒻只会暴力,矩乘根本写不出来,然后让我们找一下规律,我们发现如果我们把这个序列在mod k的意义下摆出,并且在此过程中把值为1的的数减一,我们发现他可以成为一段一段的被0(我们在此只关注减1变为0的点)区间,我们继续分析我们分析出来了这样的性质:如果存在这样的点,那么他右边的点一定是两个重复的数,而且往后是fibonacci数列(重头开始)乘第一个数,那么他之后再出现这样的0,的充要条件是其后存在一个fibonacci数是这段数第一个数的

矩阵乘法&amp;&amp;矩阵快速幂

int add(long long &x,long long y) { x+=y; x%=MOD; } Matrix mutil(Matrix x,Matrix y) { Matrix z; memset(z.a,0,sizeof(z.a)); for(int i=0;i<X;i++) { for(int k=0;k<X;k++) { if(x.a[i][k]==0) continue; for(int j=0;j<X;j++) { add(z.a[i][j],x.a[i][k]

NOI2011 兔农

http://www.lydsy.com/JudgeOnline/problem.php?id=2432 感觉是day1中最难的一题,还好出题人很良心,给了75分部分分. 还是跪拜策爷吧~Orz http://jcvb.is-programmer.com/posts/39528.html 代码奇丑...... #include<cstdio> #include<cstdlib> #include<iostream> #include<fstream> #in

挖坑#1——矩阵乘法

BZOJ1706: [usaco2007 Nov]relays 奶牛接力跑 BZOJ1898: [Zjoi2004]Swamp 沼泽鳄鱼 BZOJ2326: [HNOI2011]数学作业 BZOJ3204: [NOI2013] 矩阵游戏 BZOJ2875: [Noi2012]随机数生成器 BZOJ1009: [HNOI2008]GT考试 BZOJ3231: [Sdoi2008]递归数列 BZOJ1875: [SDOI2009]HH去散步 BZOJ2432: [Noi2011]兔农 BZOJ353

LibreOJ #100. 矩阵乘法

二次联通门 : LibreOJ #100. 矩阵乘法 /* LibreOJ #100. 矩阵乘法 矩阵乘法 注意两个矩阵宽与高相乘的顺序 */ #include <cstdio> #define Max 500 #define Mod 1000000007 int main (int argc, char *argv[]) { static long long a[Max + 1][Max + 1], b[Max + 1][Max + 1]; int N, P, M; scanf("