zoukankan      html  css  js  c++  java
  • 洛谷 P5110 块速递推

    题目大意:

    给定一个数列a满足递推式

    (An=233*an-1+666*an-2,a0=0,a1=1)

    求这个数列第n项模(10^9+7)的值,一共有T组询问

    (T<=10^7)

    (N)(64)位正整数


    首先感谢出题人的好心,凑了一个好模数,有循环节,于是复杂度骤降

    麻麻我会矩阵快速幂!

    时间复杂度约为(O(T*log_{2}n))

    但很抱歉,时间复杂度仍然不过关。

    因为,丧心病狂的出题人把T开到了(10^7)!!!

    预计得分(6*1=6)

    这意味着,我们需要在(O(1))的时间内求出每一次询问的值

    考虑这样一种做法

    我们将初始矩阵的n次方进行分块处理

    设初始矩阵为(A)

    即求出(A^1,A^2……A^{len-1}),记为(S)

    以及(A^{len},A^{len*2}……A^{len*len}),记为(P)

    然后我们会发现,这两个对应的矩阵序列都可以在(O(sqrt{n}))的时间范围内递推出来
    最后答案即为(S[n-n/len]*P[n/len])

    时间复杂度为(O(T+sqrt{n}))

    预计得分(100)

    参考代码(极丑,勿喷)

    // luogu-judger-enable-o2
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define mod 1000000007
    using namespace std;
    typedef unsigned long long ull;
    typedef long long ll;
    unsigned long long SA,SB,SC;
    void init(){scanf("%llu%llu%llu",&SA,&SB,&SC);}
    unsigned long long r()
    {
            SA^=SA<<32,SA^=SA>>13,SA^=SA<<1;
            unsigned long long t=SA;
            SA=SB,SB=SC,SC^=t^SA;return SC%(mod-1);
    }
    ull a[5][5][35000],b[5][5][35000],ans[5][5],tmp[5][5];
    
    int main()
    {
        //freopen("w.txt","r",stdin);
        a[1][1][0]=1;
        a[1][2][0]=a[2][1][0]=0;
        a[2][2][0]=1;
        a[1][1][1]=233;
        a[1][2][1]=666;
        a[2][1][1]=1;
        a[2][2][1]=0;
        for(register int g=2;g<=32000;++g)
            for(register int i=1;i<=2;++i)
            	for(register int k=1;k<=2;++k)
                	for(register int j=1;j<=2;++j)
                    	a[i][j][g]=(a[i][j][g]+(a[i][k][g-1]*a[k][j][1])%mod)%mod;
        b[1][1][0]=b[2][2][0]=1;    	
        b[1][1][1]=a[1][1][32000];
        b[1][2][1]=a[1][2][32000];
        b[2][1][1]=a[2][1][32000];
        b[2][2][1]=a[2][2][32000];
        for(register int g=2;g<=32000;++g)
            for(register int i=1;i<=2;++i)
            	for(register int k=1;k<=2;++k)
                	for(register int j=1;j<=2;++j)
                    	b[i][j][g]=(b[i][j][g]+(b[i][k][g-1]*b[k][j][1])%mod)%mod;
        ull t;
        scanf("%llu",&t);
        init();
        int tot=0;
        for(register int g=1;g<=t;++g)
        {
        	int q=r()-1;
        	if(q==-1) continue;
            tot^=((a[1][1][q%32000]*b[1][1][q/32000])%mod+(a[1][2][q%32000]*b[2][1][q/32000])%mod)%mod;
        }
        printf("%llu",tot);
    } 
    
    
  • 相关阅读:
    C# 局部函数与事件
    PHP curl_multi_strerror函数
    PHP curl_multi_setopt函数
    PHP curl_multi_select函数
    PHP curl_multi_remove_handle函数
    PHP curl_multi_init函数
    用户&权限
    HEOI2019 游记——240秒处的起死回生
    WPF 判断调用方法堆栈
    WPF 判断调用方法堆栈
  • 原文地址:https://www.cnblogs.com/HenryHuang-Never-Settle/p/10779376.html
Copyright © 2011-2022 走看看