1. 程式人生 > 實用技巧 >php與資料庫得一些操作

php與資料庫得一些操作

題面傳送門

題意:
給出 \(s_0,s_1,s_2,\dots,s_{n-1}\),對於 \(i\geq n\),有 \(m\)\(s_i\) 滿足 \(s_i\neq s_{i\bmod n}\),這 \(m\)\(s_i\) 特殊給定,其它的 \(s_i=s_{i\bmod n}\)
另有序列 \(f_i\) 滿足 \(f_0=0,f_1=1\)\(f_i=f_{i-1}s_{i-1}+f_{i-2}s_{i-2}\)
\(f_x\bmod P\)
\(1\leq n,m\leq 5\times 10^4,0\leq x\leq 10^{18}\)

Fibo納粹
粉兔:矩陣快速冪 sb 題。
我:矩陣快速冪神仙題。
這好像是上賽季的一個 jxd 作業。
首先寫出矩陣遞推式:

\([f_{i-2},f_{i-1}]\times\begin{bmatrix}0&s_{i-2}\\1&s_{i-1}\end{bmatrix}=[f_{i-1},f_i]\)

於是 \([f_{x-1},f_x]=[0,1]\times\prod\limits_{i=1}^{x-1}\begin{bmatrix}0&s_{i-1}\\1&s_{i}\end{bmatrix}\)
首先考慮 \(m=0\) 的情況。後面 \(\prod\) 的矩陣成周期性分部。所以可以求出每個週期內所有矩陣的乘積,跑個矩陣快速冪,最後的零頭暴力算一下就可以了。
接下來考慮 \(m\neq 0\)

的情況。記 \(P=\prod\limits_{i=0}^{n-1}\begin{bmatrix}0&s_i\\1&s_{(i+1)\bmod n}\end{bmatrix}\),不難發現,對於大多數週期,其中所有矩陣的乘積都為 \(P\),最多隻有 \(2m\) 個週期的乘積 \(\neq P\)
故可以對這些特殊的週期特殊計算,其它週期跑矩陣快速冪。
考慮一個特殊點 \(x_i\) 會造成什麼影響,會使 \(x_i\)\(x_i-1\) 的轉移矩陣發生變化。
所以我們對於所有 \(x_i\)\(x_i-1\) 所在的週期單獨計算它的貢獻。
我們建立 \(n\) 個矩陣 \(A_0,A_1,A_2,\dots,A_{n-1}\)
,初始 \(A_i=\begin{bmatrix}0&s_i\\1&s_{(i+1)\bmod n}\end{bmatrix}\)
對於某個週期中特殊處理的點 \(p\),我們修改 \(p\bmod n\) 轉移矩陣的值,然後求一遍所有 \(A_i\) 的乘積。處理完這個週期後再改回去。
於是此題變為:修改某個矩陣的值,求所有矩陣的乘積。
注意到矩陣是不支援除法操作的,所以這玩意兒只能用線段樹維護。
時間複雜度 \(2^3n\log n\)
細節噁心得要死。。。。

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
template<typename T> void read(T &x){
	char c=getchar();T neg=1;
	while(!isdigit(c)){if(c=='-') neg=-1;c=getchar();}
	while(isdigit(c)) x=x*10+c-'0',c=getchar();
	x*=neg;
}
const int MAXN=5e4;
const int SIZE=2;
ll x;int mod,n,m,k,b[MAXN+5];
pair<ll,int> p[MAXN+5];
ll tk[MAXN*2+5];
struct mat{
	int a[SIZE][SIZE];
	mat(){memset(a,0,sizeof(a));}
	friend mat operator *(mat x,mat y){
		mat ret;
		for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++)
			ret.a[i][j]=(ret.a[i][j]+1ll*x.a[i][k]*y.a[k][j]%mod)%mod;
		return ret;
	}
};
struct node{int l,r;mat val;} s[MAXN*4+5];
void build(int k,int l,int r){
	s[k].l=l;s[k].r=r;if(l==r) return;
	int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
void modify(int k,int p,mat x){
	if(s[k].l==s[k].r){s[k].val=x;return;}
	int mid=(s[k].l+s[k].r)>>1;
	if(p<=mid) modify(k<<1,p,x);else modify(k<<1|1,p,x);
	s[k].val=s[k<<1].val*s[k<<1|1].val;
}
mat query(int k,int l,int r){
	if(l<=s[k].l&&s[k].r<=r) return s[k].val;
	int mid=(s[k].l+s[k].r)>>1;
	if(r<=mid) return query(k<<1,l,r);
	else if(l>mid) return query(k<<1|1,l,r);
	else return query(k<<1,l,mid)*query(k<<1|1,mid+1,r);
}
mat qpow(mat x,ll e){
	mat ret;ret.a[0][0]=ret.a[1][1]=1;
	while(e){if(e&1) ret=ret*x;x=x*x;e>>=1;}
	return ret;
}
map<ll,int> mmp;
signed main(){
//	freopen("in.txt","r",stdin);
	scanf("%lld%d%d",&x,&mod,&n);x--;
	if(x==-1) return printf("0\n"),0;
	for(int i=0;i<n;i++) scanf("%d",&b[i]);scanf("%d",&m);
	for(int i=1;i<=m;i++) scanf("%lld%d",&p[i].fi,&p[i].se);
	for(int i=1;i<=m;i++) mmp[p[i].fi]=p[i].se;
	for(int i=1;i<=m;i++){
		tk[++k]=p[i].fi;
		if(p[i].fi!=n) tk[++k]=p[i].fi-1;
	}
	sort(tk+1,tk+k+1);k=unique(tk+1,tk+k+1)-tk-1;build(1,0,n-1);
	for(int i=0;i<n;i++){
		mat t;t.a[0][0]=0;t.a[1][0]=1;t.a[0][1]=b[i];
		if(!mmp[i+1]) t.a[1][1]=b[(i+1)%n];else t.a[1][1]=mmp[i+1];
		modify(1,i,t);
	}
	mat ret;
	if(x<n) ret=query(1,0,x);
	else{
		ret=query(1,0,n-1);
		if(mmp[n]){
			mat t;t.a[0][0]=0;t.a[1][0]=1;t.a[0][1]=b[n-1];t.a[1][1]=b[0];
			modify(1,n-1,t);
		}
		int cur=1,pre=0;ll pn=0;bool flg=0;
		while(cur<=k){
//			puts("-1");
//			printf("%d %d %d\n",cur,pn,pre);
			if(x/n<tk[pre+1]/n){
				ret=ret*qpow(query(1,0,n-1),(x/n)-pn-1);
				ret=ret*query(1,0,x%n);flg=1;break;
			}
			ret=ret*qpow(query(1,0,n-1),(tk[pre+1]/n)-pn-1);
			while(cur<=k&&tk[cur]/n==tk[pre+1]/n){
				ll id=tk[cur];int v1,v2;
				if(!mmp[id]) v1=b[id%n];else v1=mmp[id];
				if(!mmp[id+1]) v2=b[(id+1)%n];else v2=mmp[id+1];
//				printf("%lld %d %d %d\n",id,id%n,v1,v2);
				mat t;t.a[0][0]=0;t.a[1][0]=1;t.a[0][1]=v1;t.a[1][1]=v2;
				modify(1,id%n,t);cur++;
			}
			if((x/n)==(tk[pre+1]/n)){
				ret=ret*query(1,0,x%n);flg=1;break;
			} else ret=ret*query(1,0,n-1);
			for(int i=pre+1;i<cur;i++){
				mat t;t.a[0][0]=0;t.a[1][0]=1;
				t.a[0][1]=b[tk[i]%n];t.a[1][1]=b[(tk[i]+1)%n];
				modify(1,tk[i]%n,t);
			}
			pn=tk[pre+1]/n;pre=cur-1;
		}
		if(!flg){
//			puts("-1");
			ret=ret*qpow(query(1,0,n-1),(x/n)-pn-1);
			ret=ret*query(1,0,x%n);
		}
	}
	mat f;f.a[0][1]=1;f=f*ret;
	printf("%d\n",f.a[0][0]);
	return 0;
}
/*
3 998244353
3
1 2 1
3
3 3
4 6
10 8

20 998244353
3
100 370 250
5
7 230
23 500
5 480
15 530
19 570

100 998244353
3
1 2 1
2
3 2
5 1

1000000 998244353
3
100 370 250
5
7 230
23 500
5 480
15 530
19 570
*/