最近隊友拿來一個蠻有意思的東西
給定一個類似於斐波那契數列的東西,讓你去求它的第\(n\)項\((n<=10^{18})\),由於模數為1e9+7,可以先降一波冪,相當於\(n<=10^9+7\),要么去推下特征方程要么矩陣快速冪,但是這題把帶log的做法卡了,引出了一個被叫做光速冪的東西,但我感覺叫塊速冪更正常點...
就叫塊速冪吧,實際上很簡單,如果求\(p^q\),\(p\)已經給定,\(q\)的上限也已經確定是在\(1e12\)左右或者以下,設\(sq=\sqrt{q}\)那么我們線性預處理處理出\(p \cdots p^{sq}\),再處理出\(p^{sq},p^{2sq}\cdots\)
那看到這個式子應該很顯然了\(p^q=p^{q/sq}p^{sq}p^{q\%sq}\)
對於所有\(n<=1e12\)的詢問我們都能\(o(1)\)計算
類似板子的東西(這玩意真的有必要存板子么
struct KSM
{
int fac[MAXN];
int facp[MAXN];
ll p; //給定p
ll maxq = 1e9 + 10; //已知的p的冪次上限(maxq<=1e12)
int sqrtq;
void init(ll x)
{
sqrtq = int(sqrt(maxq)) + 1;
p = x;
//預處理到p^sqrtq
fac[0] = 1;
for (int i = 1; i <= sqrtq; i++)
fac[i] = 1LL * fac[i - 1] * p % MOD;
//再處理(p^sqtr)^sqtr
facp[0] = 1;
for (int i = 1; i <= sqrtq; i++)
facp[i] = 1LL * facp[i - 1] * fac[sqrtq] % MOD;
}
int cal(int x)
{
return 1LL * facp[x / sqrtq] * fac[x % sqrtq] % MOD;
}
}
隊友拿來的那道題
解題過程
求\(a_n=233a_{n-1}+666a_{n-2}\)
去網上搜下斐波那契通項公式怎么求就知道了
這種數列基本可以令\(a_n=p^n\)次將遞推公式化成\(p^2=233p+666\)
解得\(p_1=\frac{233+\sqrt{56953}}{2}\), \(p_2=\frac{233-\sqrt{56953}}{2}\)
\(A,B\)為任意實數,\(a_n=Ap_1^n+Bp_2^n\)
把\(a_1=1,a_2=233\)分別代入
如果把數值一開始帶進去除了會受到233和666的毒害以外毫無意義..先把\(p_1,p_2\)放在里面推一波
可以得到\(B=\frac{233-p_1}{p_2(p_2-p_1)},A=\frac{233-p_2}{p_1(p_1-p_2)}\)
所以\(B=\frac{\frac{233-\sqrt{56953}}{2}}{p_2(p_2-p_1)}=\frac{p_2}{p_2(p_2-p_1)}=\frac{1}{p_2-p_1}=\frac{1}{\sqrt{56953}}\)
同理\(A=\frac{-1}{\sqrt{56953}}\)
所以\(a_n=\frac{(233+\sqrt{56953})^n-(233-\sqrt{56953})^n}{2^n\sqrt{56953}}\)
掏出二次剩余板子找到\(\sqrt{56953}\)的二次剩余是\(188305837\)
所以在膜1e9+7條件下
\(a_n=\frac{(\frac{233+188305837}{2})^n-(\frac{233-188305837}{2})^n}{188305837}\)
\(=\frac{(94153035)^n-(905847205)^n}{188305837}\)
好像算好了 還被卡了一手常數
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/trie_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
// freopen("k.in", "r", stdin);
// freopen("k.out", "w", stdout);
// clock_t c1 = clock();
// std::cerr << "Time:" << clock() - c1 <<"ms" << std::endl;
//#pragma comment(linker, "/STACK:1024000000,1024000000")
mt19937 rnd(time(NULL));
#define de(a) cout << #a << " = " << a << endl
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define ls ((x) << 1)
#define rs ((x) << 1 | 1)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<char, char> PCC;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;
#define inf 0x3f3f3f3f
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MAXN = 1e5 + 7;
const ll MAXM = 4e5 + 7;
const ll MOD = 1e9 + 7;
const double eps = 1e-7;
ll qpw(ll a, ll b)
{
ll ans = 1;
while (b)
{
if (b & 1)
ans = (ans * a) % MOD;
(a *= a) %= MOD;
b >>= 1;
}
return ans;
}
struct KSM
{
int fac[MAXN];
int facp[MAXN];
ll p; //給定p
ll maxq = 1e9 + 10; //已知的p的冪次上限(maxq<=1e12)
int sqrtq;
void init(ll x)
{
sqrtq = int(sqrt(maxq)) + 1;
p = x;
//預處理到p^sqrtq
fac[0] = 1;
for (int i = 1; i <= sqrtq; i++)
fac[i] = 1LL * fac[i - 1] * p % MOD;
//再處理(p^sqtr)^sqtr
facp[0] = 1;
for (int i = 1; i <= sqrtq; i++)
facp[i] = 1LL * facp[i - 1] * fac[sqrtq] % MOD;
}
int cal(int x)
{
return 1LL * facp[x / sqrtq] * fac[x % sqrtq] % MOD;
}
} a, b;
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;
}
} // namespace Mker
int del(int a, int b)
{
int tmp = a - b;
if (tmp < 0)
tmp += MOD;
return tmp;
}
int main()
{
int t;
a.init(94153035), b.init(905847205);
int inv = qpw(188305837, MOD - 2);
int ans = 0;
scanf("%d", &t);
Mker::init();
while (t--)
{
int n = Mker::rand() % (MOD - 1);
ans ^= 1LL * del(a.cal(n), b.cal(n)) * inv % MOD;
}
printf("%d\n", ans);
return 0;
}
