\[\begin{eqnarray*}
x_i&=&x_{i-1}+x_{i-2}\\
x_i^2&=&x_{i-2}^2+x_{i-1}^2+2x_{i-2}x_{i-1}\\
x_{i-1}x_i&=& (X_{i-3}+x_{i-2}) (x_{i-2}+x_{i-1}) \ \
&=&2x_{i-3}x_{i-2}+x_{i-2}x_{i-1}+x_{i-3}^2+x_{i-2}^2
\end{eqnarray*}\]
Therefore, the transfer matrix can be constructed $a$ recursive.
If you wish to set $n\geq m$, you can preprocess $a^0,a^1,..., a^n$ and $a^n,a^{2n},..., a^{nn}$.
So the complexity of querying a number is $8^3$.
Total time complexity is $o (n (8^3+\log N)) $.
#include <cstdio> #include <algorithm> #include <map> #define REP (i) for (int i=0;i<8;i++) using Namespace Std;typedef long Long ll;const int n=8,m=100005;int n,m,lim,q,p,c1,c2,i,j,x,y;map<ll,int>t;inline void Read (ll&a) {char c;while (! ( ((C=getchar ()) >= ' 0 ') && (c<= ' 9 ')); a=c-' 0 '; while (((C=getchar ()) >= ' 0 ') && (c<= ' 9 ')) (a*= Ten) +=c-' 0 ';} struct mat{int a[n][n]; Mat () {Rep (i) Rep (j) a[i][j]=0;} Mat operator* (const mat&b) {Mat C; Rep (i) Rep (k) if (A[i][k]) Rep (j) if (B.a[k][j]) c.a[i][j]= (1ll*a[i][k]*b.a[k][j]+c.a[i][j])%P; return C; }}a[m],pa[m],b;inline int get (ll t) {t--; Mat C=pa[t/lim]*a[t%lim]*b; return c.a[7][0];} inline int Ask (int x,int y) {if (x>n| | Y>M) return P; ll t=1ll* (x-1) *m+y; if (T.find (T)!=t.end ()) return t[t]; return get (t);} int main () {Rep (i) a[0].a[i][i]=1; A[1].a[0][1]=1; A[1].a[1][0]=a[1].a[1][1]=1; A[1].a[2][3]=1; A[1].a[3][4]=1; a[1].a[4][3]=a[1].a[4][4]=1,a[1].a[4][6]=2; A[1].a[5][6]=1; A[1].A[6][2]=a[1].a[6][3]=a[1].a[6][6]=1,a[1].a[6][5]=2; A[1].a[7][4]=a[1].a[7][7]=1; scanf ("%d%d%d%d%d%d", &N,&M,&Q,&P,&C1,&C2); B.A[0][0]=C2; b.a[1][0]= (C1+C2)%P; b.a[2][0]=1ll*c1*c1%p; b.a[3][0]=1ll*c2*c2%p; b.a[4][0]=1ll* (C1+C2) * (C1+C2)%P; b.a[5][0]=1ll*c1*c2%p; b.a[6][0]=1ll*c2* (C1+C2)%P; b.a[7][0]= (1LL*C1*C1+1LL*C2*C2)%P; lim=n>m?n:m; for (i=2;i<=lim;i++) a[i]=a[i-1]*a[1]; for (pa[0]=a[0],i=1;i<=lim;i++) Pa[i]=pa[i-1]*a[lim]; for (i=1;i<=q;i++) {ll x, y; Read (x), read (y); if (T.find (x) ==t.end ()) t[x]=get (x); if (T.find (y) ==t.end ()) t[y]=get (y); Swap (t[x],t[y]); } for (i=x=y=1;i<n+m-1;i++) {printf ("%d", ask (x, y)); if (ask (X+1,y) <=ask (x,y+1)) X++;else y++; } return printf ("%d", ask (N,m)), 0;}
BZOJ4471: Random number generator Ⅱ