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

    前言

    已经吐了,感觉在用计算机做数学题

    题目

    洛谷

    讲解

    由于推导过程太小了,所以我适当调整了一下字体(于是就变得这么丑了QAQ)

    part1 求通项公式

    待定系数法求通项公式!(这是唯一一个好懂一点的方法了)

    我们的条件有:

    (Large{a_n=233a_{n-1}+666a_{n-2}pmod {10^9+7},a_0=0,a_1=1})

    (Large{a_{n+2}+pa_{n+1}=q(a_{n+1}+pa_n)})

    显然,我们可以得到:

    [Large{egin{cases} q-p=233\pq=666end{cases}} ]

    [Large{p=q-233,q(q-233)=666} ]

    (Large{q^2-233q-666=0})

    解得 (Large{q=dfrac{233±sqrt{56953}}{2}})

    通过循环暴力查找,我们发现 (Large{188305837^2}≡56953pmod {10^9+7})

    然后我们就可以用 (Large{188305837}) 替换 (Large{sqrt{56953}})

    我们令 (Large{q_1=dfrac{233+sqrt{56953}}{2}}=94153035)

    (Large{p_1=q_1-233}=94152802)

    (Large{b_n=a_{n+1}+p_1a_n}),显然 (Large{b_{n+1}=q_1b_n})(Large{b}) 序列为等比数列

    其中 (Large{b_1=233+p_1=q_1}),所以 (Large{b_n=q^n})

    (Large{a_{n+1}+p_1a_n=q_1^n ① })

    我们令 (Large{q_2=dfrac{233-sqrt{56953}}{2}}=905847205)

    (Large{p_2=q_2-233=905846972}) ,同理得到:

    (Large{a_{n+1}+p_2a_n=q_2^n ② })

    (Large{①-②})

    [Large{egin{aligned} a_n&=dfrac{q_1^n-q_2^n}{p_1-p_2}\ &=dfrac{94153035^n-905847205^n}{188305837}\ &=233230706(94153035^n-905847205^n)\ end{aligned}}]

    part2 优化

    通过 通项公式+费马小定理/打表 可知循环节(Large{10^9+6})

    对于每个给出的 (Large{n}) ,我们可以对其取模,使其在 (Large{[0,10^9+6)})

    part3 光速幂

    我们发现如果是直接通过上述的通项公式计算答案,复杂度仍然带 (log_2),所以我们要使用一些奇技淫巧

    显然 (Large{a^n=(a^{{n/b}})^b*a^{n\%b}},nin[0,10^9+6))

    定义函数 (Large{f(x)=(a^{x/b})^b=(a^b)^{x/b},g(x)=a^{x\%b}}) (这里的为整除)

    于是分块预处理,令 (Large{b=sqrt{10^9+6}}approx31623) 即可 (用2的幂不香吗?)

    (Large{a^n=f(n)g(n)})

    时间 (Large{O(1)})

    代码

    一份没有特别去卡常的代码

    const int MAXN = 31623 + 5;
    const int MOD = 1e9 + 7;
    int T,n,ans;
    namespace Mker
    {
    	unsigned long long SA,SB,SC;
    	void init(){scanf("%llu%llu%llu",&SA,&SB,&SC);}
    	unsigned long long Rand()
    	{
    	    SA^=SA<<32,SA^=SA>>13,SA^=SA<<1;
    	    unsigned long long t=SA;
    		SA=SB,SB=SC,SC^=t^SA;return SC;
    	}
    }
    using namespace Mker;
    
    int qpow(int x,int y)
    {
    	int ret = 1;
    	while(y){if(y & 1) ret = 1ll * ret * x % MOD;x = 1ll * x * x % MOD;y >>= 1;}
    	return ret;
    }
    
    int b = 31623;
    int f[2][MAXN],g[2][MAXN],num[2] = {94153035,905847205};
    void pre()
    {
    	f[0][0] = g[0][0] = f[1][0] = g[1][0] = 1;
    	for(int i = 0;i <= 1;++ i)
    		f[i][1] = qpow(num[i],b),g[i][1] = num[i];
    	for(int i = 2;i < b;++ i)
    	{
    		for(int j = 0;j <= 1;++ j)
    		{
    			f[j][i] = 1ll * f[j][i-1] * f[j][1] % MOD;
    			g[j][i] = 1ll * g[j][i-1] * g[j][1] % MOD;
    		}
    	}
    }
    int update(int x)
    {
    	if(x < 0) x += MOD;
    	return x;
    }
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	T = Read();
    	init();
    	pre();
    	while(T--)
    	{
    		n = Rand() % (MOD-1);
    		if(!n) continue;
    		int A = n/b,B = n%b;
    		ans ^= update((1ll * f[0][A] * g[0][B] - 1ll * f[1][A] * g[1][B]) % MOD * 233230706 % MOD);
    	}
    	Put(ans,'
    ');
    	return 0;
    }
    
  • 相关阅读:
    api封装
    计算字符串内的字出现几次
    Generator 函数的语法
    js原型链的看法
    购物车之上线版思路
    Java并发多线程面试题 Top 50
    Java NIO和IO的区别
    【转载】线程池的原理及实现
    【转载】关于SimpleDateFormat安全的时间格式化线程安全问题
    【转载】Java对象的生命周期
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/14186749.html
Copyright © 2011-2022 走看看