题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2813
题意:
定义Fibonacci数列为
F1=1,F2=1,Fi=Fi−1+Fi−2(i>=3)
。
对于某一个数
Fi
,求有多少个
Fj
能够整除
Fi
(i
可以等于j
),以及所有满足条件的j
的平方之和。询问次数
≤3∗106
,
i≤107
。
题解:
由定义不难得到
gcd(fibi,fibi+1)=gcd(fibi−1,fibi)=...=gcd(fib1,fib2)=1
以及
fibn+m=fibn−1∗fibm+fibn∗fibm+1
所以
gcd(fibn+m,fibn)=gcd(fibn−1∗fibm,fibn)=gcd(fibn−1,fibn)∗gcd(fibm,fibn)=gcd(fibm,fibn)
所以可以归纳得出
gcd(fibi,fibj)=fibgcd(i,j)
那么 fibj|fibi 等价于 j|i 。
对于每个询问直接算因子明显会超时,考虑用线性筛法来做,埃式筛法复杂度为
O(nloglogn)
,欧式筛法复杂度为
O(n)
,这里使用的是欧拉筛法。
记
e[i]
为
i
的最小质因数次数,
对于欧式筛中:
imodprime[j]>0 , i∗prime[j] 第一次遇见最小质因数,因数个数乘2, f[i∗prime[j]] 为 f[i]∗prime[j]2+f[i] (每个因子乘或不乘 prime[j] )。- imodprime[j]=0 , prime[j] 为 i∗prime[j] 的最小质因数但已经遇见过,最小质因数加1,因数个数关于最小质因数部分重算, d[i∗prime[j]] 不变, f[i∗prime[j]] 为 f[i]∗prime[j]2+f[d[i∗prime[j]]] 。
- 注意 fib1=fib2=1 ,这种情况并未算入某些奇数的答案中。
代码:
#include <cstdio> typedef long long LL; const int maxc = 664580, maxv = 10000001, mod = 1000000007; int cnt, prime[maxc], e[maxv], d[maxv], g[maxv], f[maxv], sumg, sumf; bool vis[maxv]; int main() { int Q, q, A, B, C; scanf("%d%d%d%d%d", &Q, &q, &A, &B, &C); A %= C, B %= C; g[1] = f[1] = 1; for(int i = 2; i <= C; ++i) { if(!vis[i]) { prime[cnt++] = i; e[i] = d[i] = 1; g[i] = 2; f[i] = ((LL)i * i + 1) % mod; } for(int j = 0, k; j < cnt && (k = i * prime[j]) <= C; ++j) { vis[k] = 1; if(i % prime[j] == 0) { e[k] = e[i] + 1; g[k] = (g[i] / (e[i] + 1)) * (e[k] + 1); d[k] = d[i]; f[k] = (f[i] * ((LL)prime[j] * prime[j] % mod) + f[d[i]]) % mod; break; } else { e[k] = 1; d[k] = i; g[k] = g[i] << 1; f[k] = f[i] * (((LL)prime[j] * prime[j] + 1) % mod) % mod; } } } while(Q--) { sumg += g[q] + (q & 1); sumf += f[q] + 4 * (q & 1); if(sumg >= mod) sumg -= mod; if(sumf >= mod) sumf -= mod; q = (q * (LL)A + B) % C + 1; } printf("%d\n%d\n", sumg, sumf); return 0; }