先简述一下题目吧:
f[0] = 0;
f[n] = g(n, f[n-1]);
g(x, y) = ((y-1)x^5 + x^3 -x*y + 3*x + 7*y) % 9973
如果直接去算,n<=10^8,那么时间一定是不够的。所以就是要加速计算,我感觉一定有周期性可以利用,但由于n的原因,我没能看出来周期性在哪里。
后面看了书上的题解。
先将f[n] = g(n, f[n-1])和g(x, y) = ((y-1)x^5 + x^3 -x*y + 3*x + 7*y) % 9973结合
f(x) =( (x^5 + x + 7)*y + (-x^5 + x^3 + 3*x) ) % 9973
令M = 9973
然后当x=n时和x=n-k*M时
(x^5 + x + 7) % M 的值是一样的
(-x^5 + x^3 + 3*x) % M的值是一样的
所以存在一个周期的线性关系,既
f[x] = A * f[x-M] + B
f[x-M] = A * f[x - 2*M] + B
.......
f[n%M+M] = A * f[n%M] + B
(这一点我想了挺久,大家不明白的可以手动模拟着推一推就懂了)
所以就只要先算出f[n%M]
然后从n%M+1到n%M+M计算出A和B的值
然后根据f[n] = A * f[n-M] + B计算出f[n]
那么时间复杂度是O(n%M + [n / M]) 也就是10000左右就好了
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
const int M=9973;
int A = 1,B = 0;
int f[50000];
//计算a^t mod t
int f_pow(int a, int t)
{
int ans = 1,i;
for (i=0; i<t; i++)
ans = (ans*a) % M;
return ans;
}
//将a模M
void f_mol(int &a)
{
a %= M;
if (a < 0)
a += M;
}
//计算x^5-x+7
int f1(int x)
{
int ans=0;
ans = (f_pow(x, 5) - x + 7);
f_mol(ans);
return ans;
}
//计算x^5+x^3+3x
int f2(int x)
{
int ans=0;
ans = -1*(f_pow(x, 5)) + f_pow(x, 3) + 3*x;
f_mol(ans);
return ans;
}
int main()
{
int i,j,n,m,l1,l2,ans;
scanf("%d", &n);
m = n % M;
f[0] = 0;
//直接计算出f[n%M]的值
for (i=1; i<=m; i++)
{
l1 = f1(i);
l2 = f2(i);
f[i] = l1*f[i-1] + l2;
f_mol(f[i]);
}
//计算出f[t]=A*f[t-M]+B中的A和B的值
for (i=m+1; i<=m+M; i++)
{
l1 = f1(i);
l2 = f2(i);
f[i] = l1*f[i-1] + l2;
A *= l1;
B = B*l1 + l2;
f_mol(f[i]);
f_mol(A);
f_mol(B);
}
//通过f[t]=A*f[t-M]+B,计算f[n%M],f[(n%M)+M],....,f[n-2*M],f[n-M],f[n]。
ans = f[m];
while (m < n)
{
ans = A*ans+B;
f_mol(ans);
m += M;
}
printf("%d\n", ans);
return 0;
}