【模板】類歐幾里得


模板
傳送門

由於太懶以下直接用a/baba/b表示\lfloor \frac a b\rfloor
如果有乘除疊一起會單獨打括號區分乘除的地方

1f1、f:

f(a,b,c,n)=i=0n(ai+b)/cf(a,b,c,n)=\sum_{i=0}^n(ai+b)/c
a=0a=0
f=(n+1)(b/c)f=(n+1)(b/c)
否則若有acbca\geq c ||b\geq c
f=i=0n(ia%c+b%c)/c+i(a/c)+(b/c)f=\sum_{i=0}^{n}(ia\%c+b\%c)/c+i(a/c)+(b/c)
=f(a%c,b%c,c,n)+n(n+1)/2(a/c)+(n+1)(b/c)=f(a\%c,b\%c,c,n)+n*(n+1)/2*(a/c)+(n+1)(b/c)
a<ca<cb<cb<c
m=(an+b)/cm=(an+b)/c
f=i=0nj=1m[j(ai+b)/c]f=\sum_{i=0}^n\sum_{j=1}^{m}[j\le(ai+b)/c]
f=i=0nj=0m1[j+1<(ai+b+1)/c]f=\sum_{i=0}^n\sum_{j=0}^{m-1}[j+1<(ai+b+1)/c]
=i=0nj=0m1[i>(jc+cb1)/a]=\sum_{i=0}^n\sum_{j=0}^{m-1}[i>(jc+c-b-1)/a]
=j=0m1i=0n[i>(jc+cb1)/a]=\sum_{j=0}^{m-1}\sum_{i=0}^n[i>(jc+c-b-1)/a]
=j=0m1n(jc+cb1)/a=\sum_{j=0}^{m-1}n-(jc+c-b-1)/a
=nmf(c,cb1,a,m1)=nm-f(c,c-b-1,a,m-1)

顯然複雜度爲O(logn)O(logn)

2:g,h2:g,h
g(a,b,c,n)=i=0n((ai+b)/c)2g(a,b,c,n)=\sum_{i=0}^n((ai+b)/c)^2
h(a,b,c,n)=i=0ni((ai+b)/c)h(a,b,c,n)=\sum_{i=0}^ni((ai+b)/c)
首先類似
a=0a=0
g=(n+1)(b/c)2,h=n(n+1)/2(b/c)g=(n+1)(b/c)^2,h=n*(n+1)/2*(b/c)

acbca\geq c||b\geq c
類似之前ff
拆開得到
g=g(a%c,b%c,c,n)+2(a/c)h(a%c,b%c,c,n)+2(b/c)f(a%c,b%c,c,n)+(a/c)(b/c)n(n+1)+n(n+1)(2n+1)/6(a/c)2+(n+1)(b/c)2g=g(a\%c,b\%c,c,n)+2*(a/c)*h(a\%c,b\%c,c,n)+2*(b/c)*f(a\%c,b\%c,c,n)\\+(a/c)*(b/c)*n*(n+1)+n*(n+1)*(2n+1)/6*(a/c)^2+(n+1)*(b/c)^2
h=h(a%c,b%c,c,n)+n(n+1)(2n+1)/6(a/c)+n(n+1)/2(b/c)h=h(a\%c,b\%c,c,n)+n*(n+1)*(2n+1)/6*(a/c)+n*(n+1)/2*(b/c)

a<ca<cb<cb<c
m=(an+b)/cm=(an+b)/c
g=i=0n((ai+b)/c)2g=\sum_{i=0}^n((ai+b)/c)^2
=2i=0nj=1(ai+b)/cji=0n(ai+b)/c=f(a,b,c,n)+2i=0nj=0m1(j+1)[jc+c<ai+b+1]=f+2j=0m1(j+1)[i>(jc+cb1)/a]=f+2j=0m1(j+1)(n(jc+cb1)/a)=f(a,b,c,n)+m(m+1)n2f(c,cb1,a,m1)2h(c,cb1,a,m1)=2*\sum_{i=0}^n\sum_{j=1}^{(ai+b)/c}j-\sum_{i=0}^n(ai+b)/c\\ =-f(a,b,c,n)+2\sum_{i=0}^n\sum_{j=0}^{m-1}(j+1)[jc+c<ai+b+1]\\ =-f+2\sum_{j=0}^{m-1}(j+1)[i>(jc+c-b-1)/a]\\ =-f+2\sum_{j=0}^{m-1}(j+1)(n-(jc+c-b-1)/a)\\ =-f(a,b,c,n)+m(m+1)n-2f(c,c-b-1,a,m-1)-2h(c,c-b-1,a,m-1)

h=i=0ni((ai+b)/c)=i=0nij=0m1[i>(jc+cb1)/a]=j=0m1i=0ni[i>(jc+cb1)/a]=mn(n+1)/2j=0m1i=0ni[i(jc+cb1)/a]=mn(n+1)/2j=0m1i=0(jc+cb1)/ai=mn(n+1)/2j=0m1((jc+cb1)/a)((jc+cb1)/a+1)/2=12(mn(n+1)i=0m1((jc+cb1)/a)2i=0m1((jc+cb1)/a))=12(mn(n+1)f(c,cb1,a,m1)g(c,cb1,a,m1))h=\sum_{i=0}^ni((ai+b)/c)\\ =\sum_{i=0}^ni\sum_{j=0}^{m-1}[i>(jc+c-b-1)/a]\\ =\sum_{j=0}^{m-1}\sum_{i=0}^ni[i>(jc+c-b-1)/a]\\ =m*n*(n+1)/2-\sum_{j=0}^{m-1}\sum_{i=0}^ni[i\le(jc+c-b-1)/a]\\ =m*n*(n+1)/2-\sum_{j=0}^{m-1}\sum_{i=0}^{(jc+c-b-1)/a}i\\ =m*n*(n+1)/2-\sum_{j=0}^{m-1}((jc+c-b-1)/a)*((jc+c-b-1)/a+1)/2\\ =\frac 1 2(m*n*(n+1)-\sum_{i=0}^{m-1}((jc+c-b-1)/a)^2-\sum_{i=0}^{m-1}((jc+c-b-1)/a))\\ =\frac 1 2(m*n*(n+1)-f(c,c-b-1,a,m-1)-g(c,c-b-1,a,m-1))

複雜度O(logn)O(logn)


萬能歐幾里得
傳送門
i=1lAiB(pi+r)/q\sum_{i=1}^lA^iB^{(pi+r)/q}
考慮這樣一個操作
維護一個三元組a,b,sa,b,s
考慮一條線段y=(px+r)/qy=(px+r)/q
(0,L](0,L]內從左往右走
每當線段碰到x=cx=c時令a=aAa=a*A
每當碰到y=cy=c時令b=bBb=b*B
對於整點先進行y=cy=c再進行x=cx=c
每次操作後令new s=s+ABnew \ s=s+A*B

顯然這和原來求得東西等價
觀察到這是一個線性變換,擁有結合律

萬能歐幾里得能利用壓縮信息在O(logT(n))O(logT(n))的時間求出這個東西
考慮當rqr\geq q時令r=r%qr=r\%q不會對操作序列產生影響
只是初始的bb會變成br/qb^{r/q},先做即可
設函數爲f(p,q,r,l,a,b)f(p,q,r,l,a,b)

pqp\geq q
k=(p/q)k=(p/q)
那麼考慮線段爲y=kx+((p%q)x+r)/qy=kx+((p\%q)x+r)/q
那麼每次xx加一前必定會至少有kkyy的變化
於是可以直接遞歸f(p%q,q,r,l,bka,b)f(p\%q,q,r,l,b^{k}*a,b)

否則考慮可以翻轉座標軸,將x,yx,y反過來
翻轉後的函數就是反函數
x=(qyr)/px=(qy-r)/p
但是這時候如果按照原來的在整點時候的計算順序就反了
於是考慮變成x=(qyr1)/px=(qy-r-1)/p強制先計算xx
k=(pl+r)/qk=(pl+r)/q
考慮翻轉後求y(1,k]y\in(1,k]範圍內的
那顯然要先把前面沒計算的部分求了
就是a(qr1)/pba^{(q-r-1)/p}*b
考慮把y(1,k]y(0,k1]y\in(1,k]\rightarrow y\in(0,k-1]
那麼函數就變成x=(qy+qr1)/px=(qy+q-r-1)/p
於是遞歸f(q,p,qrl,k1,b,a)f(q,p,q-r-l,k-1,b,a)
但是kk之後可能還有一些xx沒被計算到
個數是l(kqr1)/pl-(kq-r-1)/p
於是在後面乘上一個al(kqr1)/pa^{l-(kq-r-1)/p}即可

複雜度應該是O(n3log)O(n^3log)

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define ll long long
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob)?EOF:*ib++;
}
inline int read(){
    char ch=gc();
    int res=0;bool f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
inline ll readll(){
    char ch=gc();
    ll res=0;bool f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
inline int readstring(char *s){
	int top=0;char ch=gc();
	while(isspace(ch))ch=gc();
	while(!isspace(ch)&&ch!=EOF)s[++top]=ch,ch=gc();
	return top;
}
template<typename tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<typename tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int mod=998244353;
inline int add(int a,int b){return (a+=b)>=mod?(a-mod):a;}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){static ll r;r=1ll*a*b;return (r>=mod)?(r%mod):r;}
inline void Add(int &a,int b){(a+=b)>=mod?(a-=mod):0;}
inline void Dec(int &a,int b){a-=b,a+=a>>31&mod;}
inline void Mul(int &a,int b){static ll r;r=1ll*a*b;a=(r>=mod)?(r%mod):r;}
inline int ksm(int a,int b,int res=1){if(a==0&&b==0)return 0;for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
inline int fix(ll x){return x%=mod,(x<0)?x+mod:x;}
int n;
struct mat{
	int a[21][21];
	mat(){memset(a,0,sizeof(a));}
	friend inline mat operator *(cs mat &a,cs mat &b){
		mat c;
		for(int i=0;i<n;i++)
		for(int k=0;k<n;k++)
		for(int j=0;j<n;j++)
		Add(c.a[i][j],mul(a.a[i][k],b.a[k][j]));
		return c;
	}
	friend inline mat operator +(cs mat &a,cs mat &b){
		mat c;
		for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
		c.a[i][j]=add(a.a[i][j],b.a[i][j]);
		return c;
	}
}I,O,A,B;
struct node{
	mat a,b,s;
	node(mat _a,mat _b,mat _c):a(_a),b(_b),s(_c){}
	friend inline node operator *(cs node &x,cs node &y){
		return node(x.a*y.a,x.b*y.b,x.s+x.a*y.s*x.b);
	}
	friend inline node operator ^(node x,ll b){
		node res(I,I,O);
		for(;b;b>>=1,x=x*x)if(b&1)res=res*x;
		return res;
	}
};
node solve(ll p,ll q,ll r,ll l,cs node &a,cs node &b){
	if(l==0)return node(I,I,O);
	r%=q;
	if(p>=q)return solve(p%q,q,r,l,(b^(p/q))*a,b);
	ll k=((long double)p*l+r)/q;
	if(k==0)return a^l;
	ll v=((long double)k*q-r-1)/p;
	v=l-v;
	return (a^((q-r-1)/p))*b*solve(q,p,q-r-1,k-1,b,a)*(a^v);
}
ll p,q,r,l;
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	#endif
	p=readll(),q=readll(),r=readll(),l=readll(),n=read();
	for(int i=0;i<n;i++)
	for(int j=0;j<n;j++)A.a[i][j]=read();
	for(int i=0;i<n;i++)
	for(int j=0;j<n;j++)B.a[i][j]=read();
	for(int i=0;i<n;i++)I.a[i][i]=1;
	node ans=(node(I,B,O)^(r/q))*solve(p,q,r,l,node(A,I,A),node(I,B,O));
	for(int i=0;i<n;i++,puts(""))
	for(int j=0;j<n;j++)
	cout<<ans.s.a[i][j]<<" ";
	return 0;
}

用這個方法就可以很簡單的水掉前面那麼一大截複雜的計算的式子
但是懶得做了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章