zoukankan      html  css  js  c++  java
  • BZOJ3286 Fibonacci矩阵 矩阵 快速幂 卡常

    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ3286


    题意概括

    n,m,a,b,c,d,e,f<=10^1000000


    题解

      神奇的卡常题目。

      在此感谢"zhouzixuan"——bzoj 3286: Fibonacci矩阵

      学习他,才15秒卡过此题。

      这题的做法应该很明显的,学过矩阵快速幂的大概几眼就看出来了。

      对于每一行的转移,是相同的,所以矩阵快速幂可以搞定行与行之间的转移。

      然后对于某一行,其实大部分的转移是和abc有关的,同理也可用矩阵快速幂搞定。

      但是如果折半的话,矩阵快速幂的复杂度为log2(n)*len(n)   (高精度运算复杂度)

      要TLE。

      然后我们发现,如果10位10位走,就不用跑高精度了。那么时间复杂度理论上就可以过去了。

      但是这题神坑。

      卡常!!!!!!!

      那么,我们研究矩阵,发现,我们构造的矩阵,有一列(或者一行)的3个数的值总是不变的。

      那么,我们可以减少循环??

      然后,去掉循环,手写9个运算式又可以省去循环变量的几个运算的复杂度。

      然后,仍然不够。我们发现数组访问有点慢,那么我们把数组去掉,改成一个一个的变量。

      这样大概可以快上4倍。

      然后,我们发现之前的那3个不变的也没用了,直接不运算了,其余的按照原先的运算,其中涉及之前的那3个的就把变量名改成值就可以了。

      然后发现还是TLE了。

      您千万不要气馁。

      对于矩阵快速幂中,我原先的版本是这样的:

    Mat MatPow(Mat x,int *v,int len){
        Mat ans(1),xx;
        for (int i=1;i<=len;i++){
            for (int j=v[i];j--;)
                ans=ans*x;
            xx=x=x*x,x=x*x,x=x*x,x=x*xx;
        }
        return ans;
    }
    

      其实,这个时候,我们不仅要在x上面花时间,又要在ans上花时间,所以,我们要想办法卡。

      事实上,我们可以这样:(省掉了约1/3的时间)

      

    inline Mat MatPow(Mat x,int *v,int len){
        Mat ans(1),xx;
        Mat fac[10];
        fac[0].set(1);
        for (int i=1;i<=9;i++)
            fac[i]=fac[i-1]*x;
        for (int i=len;i>=1;i--)
            ans=MatPow(ans)*fac[v[i]];
        return ans;
    }
    

      

      然后我就过去了。(心)累死了。


    update 2017-12-22

    在写BZOJ3240的时候,突然发现我当初在写最后的MatPow的时候,有重复计算。然后舍去了重复计算,卡掉了1/3的常数,现在是10秒了。


    代码

    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    typedef long long LL;
    const int mod=2012182013;
    struct BigInt{
    	static const int MaxL=1000005;
    	int v[MaxL],len;
    	inline bool isd(char ch){return '0'<=ch&&ch<='9';}
    	inline void read(){
    		len=0;
    		char ch=getchar();
    		while (!isd(ch))
    			ch=getchar();
    		while (isd(ch))
    			v[++len]=ch-48,ch=getchar();
    		for (int i=1;i<=len/2;i++)
    			swap(v[i],v[len+1-i]);
    	}
    	inline void minus(){
    		v[1]--;
    		for (int i=1;i<len;i++)
    			if (v[i]<0)
    				v[i]+=10,v[i+1]--;
    			else
    				break;
    		while (len&&!v[len])
    			len--;
    	}
    };
    inline bool isd(char ch){return '0'<=ch&&ch<='9';}
    inline LL getMODed(){
    	char ch=getchar();
    	while (!isd(ch))
    		ch=getchar();
    	LL res=0;
    	while (isd(ch))
    		res=(res*10+ch-48)%mod,ch=getchar();
    	return res;
    }
    struct Mat{
    	LL v11,v12,v21,v22,v31,v32;
    	inline Mat (){}
    	inline Mat (int x){(*this).set(x);}
    	inline void set(int x){
    		v11=v12=v21=v22=v31=v32=0;
    		if (x==1)
    			v11=v22=1;
    	}
    	inline void build(int a,int b,int c){
    		v11=0,v12=a;
    		v21=1,v22=b;
    		v31=0,v32=c;
    	}
    	inline Mat operator * (Mat &b){
    		Mat ans;
    		ans.v11=(v11*b.v11+v12*b.v21)%mod;
    		ans.v12=(v11*b.v12+v12*b.v22)%mod;
    		ans.v21=(v21*b.v11+v22*b.v21)%mod;
    		ans.v22=(v21*b.v12+v22*b.v22)%mod;
    		ans.v31=(v31*b.v11+v32*b.v21+b.v31)%mod;
    		ans.v32=(v31*b.v12+v32*b.v22+b.v32)%mod;
    		return ans;
    	}
    };
    inline Mat MatPow(Mat x){
    	Mat ans(1);
    	for (int y=10;y;y>>=1,x=x*x)
    		if (y&1)
    			ans=ans*x;
    	return ans;
    }
    inline Mat MatPow(Mat x,int *v,int len){
    	Mat ans(1),xx;
    	Mat fac[10];
    	fac[0].set(1);
    	for (int i=1;i<=9;i++)
    		fac[i]=fac[i-1]*x;
    	for (int i=len;i>=1;i--)
    		ans=MatPow(ans)*fac[v[i]];
    	return ans;
    }
    LL a,b,c,d,e,f;
    BigInt n,m;
    Mat Mx,My,en,res;
    int main(){
    	n.read(),m.read();
    	a=getMODed(),b=getMODed(),c=getMODed();
    	d=getMODed(),e=getMODed(),f=getMODed();
    	Mx.build(a,b,c),My.build(d,e,f);
    	m.minus(),m.minus(),n.minus();
    	res=MatPow(Mx,m.v,m.len);
    	en=MatPow(res*My*My,n.v,n.len)*res;
    	printf("%lld",(en.v12+en.v22+en.v32)%mod);
    	return 0;
    }
    

      

  • 相关阅读:
    Atcoder Grand Contest 003 题解
    Atcoder Grand Contest 002 题解
    Atcoder Grand Contest 001 题解
    网络流24题
    AGC005D ~K Perm Counting
    loj6089 小Y的背包计数问题
    CF932E Team Work
    组合数学相关
    SPOJ REPEATS
    [SDOI2008]Sandy的卡片
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ3286.html
Copyright © 2011-2022 走看看