使用矩陣乘法+線段樹解決區間歷史和問題的一種通用解法

文章目錄

  • 前言
  • P8868 [NOIP2022] 比賽
  • CF1824D
  • P9990/2020 ICPC EcFinal G

前言

一般解決普通的區間歷史和,只需要定義輔助 c = h s ? t ? a c=hs-t\cdot a c=hs?t?a h s hs hs是歷史和, a a a是區間和, t t t是時間戳,維護 a , c a,c a,c數組的區間加即可

但是如果題目更復雜一點,就要設置不同的tag,考慮下放順序和影響,非常費腦子

一種無腦的方法就是構造矩陣,如果單純使用普通的矩陣乘法,那么總復雜度會多 C 3 C^3 C3,其中 C C C為向量長度

本文的目的就是優化矩陣乘法的過程,實際上就是對矩陣乘法循環展開,只不過個人認為能更優雅一點罷了

P8868 [NOIP2022] 比賽

題意給出 a , b a,b a,b兩個數組,多次詢問, [ L , R ] [L,R] [L,R]的所有子區間的 max ? a i ? max ? b j \max a_i \cdot \max b_j maxai??maxbj?,也就是求 ∑ L ≤ l ≤ r ≤ R max ? l ≤ i ≤ r a i ? max ? l ≤ i ≤ r b i \sum_{L \leq l \leq r \leq R }\max_{l \leq i \leq r}a_i \cdot \max_{l \leq i \leq r} b_i LlrR?lirmax?ai??lirmax?bi?

考慮對所有詢問離線,從左到右掃一遍,維護以 i i i為右端點的答案,詢問就是查詢區間 max ? a ? max ? b \max a \cdot \max b maxa?maxb的歷史和

a , b a,b a,b分別維護兩個單調棧即可用線段樹更新

線段樹每個節點維護 [ a , b , a b , c , l e n ] [a,b,ab,c,len] [a,b,ab,c,len]表示區間 a i a_i ai?的和, b i b_i bi?的和, a i b i a_ib_i ai?bi?的和, a i b i a_ib_i ai?bi?的歷史和,區間長度

那么對于區間 a a a k k k,有
( a b a b c l e n ) T ? ( 1 0 0 0 0 0 1 k 0 0 0 0 1 0 0 0 0 0 1 0 k 0 0 0 1 ) = ( a + k ? l e n b a b + k b c l e n ) T \begin{pmatrix} a\\b\\ab\\c\\len \end{pmatrix}^T\cdot \begin{pmatrix} 1&0&0&0&0\\ 0&1&k&0&0\\ 0&0&1&0&0\\ 0&0&0&1&0\\ k&0&0&0&1 \end{pmatrix}= \begin{pmatrix} a+k \cdot len\\b\\ab+kb\\c\\len \end{pmatrix}^T ?ababclen? ?T? ?1000k?01000?0k100?00010?00001? ?= ?a+k?lenbab+kbclen? ?T
同理,區間 b b b k k k,有
( 1 0 k 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 k 0 0 1 ) \begin{pmatrix} 1&0&k&0&0\\ 0&1&0&0&0\\ 0&0&1&0&0\\ 0&0&0&0&1\\ 0&k&0&0&1 \end{pmatrix} ?10000?0100k?k0100?00000?00011? ?
更新區間歷史和
( 1 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 1 ) \begin{pmatrix} 1&0&0&0&0\\ 0&1&0&0&0\\ 0&0&1&1&0\\ 0&0&0&1&0\\ 0&0&0&0&1 \end{pmatrix} ?10000?01000?00100?00110?00001? ?
雖然矩陣乘法是 5 3 5^3 53,但是可以發現很多狀態是一直為 0 0 0,也就是沒有用的,要想找到這些狀態,我們只需要將所有矩陣初始不為0的狀態設為1,跑一遍傳遞閉包,就可以知道所有狀態,這里25個狀態一共只有14個狀態合法(實際上可以9個,主對角線恒為1)

然后我們可以打表來代替手寫,打表代碼如下

void solve(){vector<vector<int>> f={{1,0,1,0,0},{0,1,1,0,0},{0,0,1,1,0},{0,0,0,1,0},{1,1,0,0,1}};const int n=f.size();for(int k=0;k<n;k++){for(int i=0;i<n;i++){for(int j=0;j<n;j++)f[i][j]|=f[i][k]&f[k][j];}}string s="int ";for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(f[i][j])s+="x"+to_string(i)+to_string(j)+",";}}s.pop_back();s+=";\n";s+="\n\nMatrix * Matrix:\n";for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(!f[i][j])continue;s+="res.x"+to_string(i)+to_string(j)+"=";for(int k=0;k<n;k++){if(f[i][k]&f[k][j])s+="a.x"+to_string(i)+to_string(k)+"*b.x"+to_string(k)+to_string(j)+"+";}s.pop_back();s+=";\n";}}s+="\n\nVec * Matrix:\n";for(int i=0;i<n;i++){s+="res.x0"+to_string(i)+"=";for(int j=0;j<n;j++){if(f[j][i]){s+="a.x0"+to_string(j)+"*b.x"+to_string(j)+to_string(i)+"+";}}s.pop_back();s+=";\n";}s.pop_back();cout<<s;
}
/*
打印結果:
int x00,x02,x03,x11,x12,x13,x22,x23,x33,x40,x41,x42,x43,x44;Matrix * Matrix:
res.x00=a.x00*b.x00;
res.x02=a.x00*b.x02+a.x02*b.x22;
res.x03=a.x00*b.x03+a.x02*b.x23+a.x03*b.x33;
res.x11=a.x11*b.x11;
res.x12=a.x11*b.x12+a.x12*b.x22;
res.x13=a.x11*b.x13+a.x12*b.x23+a.x13*b.x33;
res.x22=a.x22*b.x22;
res.x23=a.x22*b.x23+a.x23*b.x33;
res.x33=a.x33*b.x33;
res.x40=a.x40*b.x00+a.x44*b.x40;
res.x41=a.x41*b.x11+a.x44*b.x41;
res.x42=a.x40*b.x02+a.x41*b.x12+a.x42*b.x22+a.x44*b.x42;
res.x43=a.x40*b.x03+a.x41*b.x13+a.x42*b.x23+a.x43*b.x33+a.x44*b.x43;
res.x44=a.x44*b.x44;Vec * Matrix:
res.x00=a.x00*b.x00+a.x04*b.x40;
res.x01=a.x01*b.x11+a.x04*b.x41;
res.x02=a.x00*b.x02+a.x01*b.x12+a.x02*b.x22+a.x04*b.x42;
res.x03=a.x00*b.x03+a.x01*b.x13+a.x02*b.x23+a.x03*b.x33+a.x04*b.x43;
res.x04=a.x04*b.x44;
*/

然后我們就可以利用打印結果,快速套上線段樹板子

struct Matrix{int x00,x02,x03,x11,x12,x13,x22,x23,x33,x40,x41,x42,x43,x44;
};
struct Vec{int x00,x01,x02,x03,x04;
};
Matrix operator*(const Matrix &a,const Matrix &b){Matrix res;res.x00=a.x00*b.x00;res.x02=a.x00*b.x02+a.x02*b.x22;res.x03=a.x00*b.x03+a.x02*b.x23+a.x03*b.x33;res.x11=a.x11*b.x11;res.x12=a.x11*b.x12+a.x12*b.x22;res.x13=a.x11*b.x13+a.x12*b.x23+a.x13*b.x33;res.x22=a.x22*b.x22;res.x23=a.x22*b.x23+a.x23*b.x33;res.x33=a.x33*b.x33;res.x40=a.x40*b.x00+a.x44*b.x40;res.x41=a.x41*b.x11+a.x44*b.x41;res.x42=a.x40*b.x02+a.x41*b.x12+a.x42*b.x22+a.x44*b.x42;res.x43=a.x40*b.x03+a.x41*b.x13+a.x42*b.x23+a.x43*b.x33+a.x44*b.x43;res.x44=a.x44*b.x44;return res;
}
Vec operator * (const Vec &a,const Matrix &b){Vec res;res.x00=a.x00*b.x00+a.x04*b.x40;res.x01=a.x01*b.x11+a.x04*b.x41;res.x02=a.x00*b.x02+a.x01*b.x12+a.x02*b.x22+a.x04*b.x42;res.x03=a.x00*b.x03+a.x01*b.x13+a.x02*b.x23+a.x03*b.x33+a.x04*b.x43;res.x04=a.x04*b.x44;return res;
}
Vec operator +(const Vec &a,const Vec &b){return {a.x00+b.x00,a.x01+b.x01,a.x02+b.x02,a.x03+b.x03,a.x04+b.x04};
}
Matrix I={1,0,0,1,0,0,1,0,1,0,0,0,0,1};
Matrix C={1,0,0,1,0,0,1,1,1,0,0,0,0,1};
Matrix getA(int k){return Matrix{1,0,0,1,k,0,1,0,1,k,0,0,0,1};
}
Matrix getB(int k){return Matrix{1,k,0,1,0,0,1,0,1,0,k,0,0,1};
}
vector<int> a,b;
struct SegmentTree{struct Node{Vec v;Matrix tag=I;bool lazy=0;};vector<Node> t;void init(int n){t=vector<Node>(n<<2);build(1,1,n);}void pushup(int p){t[p].v=t[p<<1].v+t[p<<1|1].v;}void pushtag(int p,const Matrix &m){t[p].v=t[p].v*m;t[p].tag=t[p].tag*m;t[p].lazy=1;}void pushdown(int p){if(t[p].lazy){pushtag(p<<1,t[p].tag);pushtag(p<<1|1,t[p].tag);t[p].lazy=0;t[p].tag=I;}}void build(int p,int l,int r){if(l==r){t[p].v={a[l],b[l],a[l]*b[l],0,1};return;}int mid=l+r>>1;build(p<<1,l,mid);build(p<<1|1,mid+1,r);pushup(p);}void modify(int p,int l,int r,int ql,int qr,const Matrix &x){if(ql<=l&&r<=qr){pushtag(p,x);return;}pushdown(p);int mid=l+r>>1;if(ql<=mid)modify(p<<1,l,mid,ql,qr,x);if(qr>mid)modify(p<<1|1,mid+1,r,ql,qr,x);pushup(p);}int query(int p,int l,int r,int ql,int qr){if(ql<=l&&r<=qr)return t[p].v.x03;pushdown(p);int res=0,mid=l+r>>1;if(ql<=mid)res+=query(p<<1,l,mid,ql,qr);if(qr>mid)res+=query(p<<1|1,mid+1,r,ql,qr);return res;}
} t;
void solve(){int n,m;cin>>m>>n;vector<int> sta(n+1),stb(n+1);a.assign(n+1,0);b.assign(n+1,0);for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++)cin>>b[i];t.init(n);cin>>m;vector<PII> Que[n+1];for(int i=0;i<m;i++){int l,r;cin>>l>>r;Que[r].emplace_back(l,i);}vector<int> ans(m);int at=0,bt=0;for(int i=1;i<=n;i++){while(at&&a[sta[at]]<a[i]){t.modify(1,1,n,sta[at-1]+1,sta[at],getA(a[i]-a[sta[at]]));--at;}sta[++at]=i;while(bt&&b[stb[bt]]<b[i]){t.modify(1,1,n,stb[bt-1]+1,stb[bt],getB(b[i]-b[stb[bt]]));--bt;}stb[++bt]=i;t.modify(1,1,n,1,i,C);for(auto [l,id]:Que[i]){ans[id]=t.query(1,1,n,l,i);}}for(int i=0;i<m;i++)cout<<ans[i]<<"\n";
}

這樣就可以通過此題了,復雜度大概能快個10倍

CF1824D

在這里插入圖片描述
首先一樣的套路,離線從左到右掃,差分一下,即求 ∑ i = l r ∑ j = 1 y g ( i , j ) ? ∑ i = l x ? 1 g ( i , j ) \sum_{i=l}^r\sum_{j=1}^yg(i,j)-\sum_{i=l}^{x-1}g(i,j) i=lr?j=1y?g(i,j)?i=lx?1?g(i,j)

用一個set維護最后一個數出現的位置,那么 g ( i , j ) 就是 s e t 里面第一個大于等于 g(i,j)就是set里面第一個大于等于 g(i,j)就是set里面第一個大于等于i 的位置; 的位置; 的位置;對于一個 g ( i , j ) g(i,j) g(i,j),考慮哪些 i i i的貢獻發生改變,手玩一下發現是一段區間覆蓋,可以用區間加代替

那么區間加,區間歷史和,就是套版子了
維護向量 [ s u m , h i s , l e n ] [sum,his,len] [sum,his,len]表示和,歷史和,長度

區間加矩陣:
( 1 0 0 0 1 0 k 0 1 ) \begin{pmatrix} 1&0&0\\ 0&1&0\\ k&0&1 \end{pmatrix} ?10k?010?001? ?
更新矩陣
( 1 1 0 0 1 0 1 0 1 ) \begin{pmatrix} 1&1&0\\ 0&1&0\\ 1&0&1 \end{pmatrix} ?101?110?001? ?

打表簡化常數,最終發現只需要維護6個變量
按照之前的步驟寫,不需要手動卡常也能過

struct Matrix{int x00,x01,x11,x20,x21,x22;
};
struct Vec{int x00,x01,x02;
};
Matrix operator*(const Matrix &a,const Matrix &b){Matrix res;res.x00=a.x00*b.x00;res.x01=a.x00*b.x01+a.x01*b.x11;res.x11=a.x11*b.x11;res.x20=a.x20*b.x00+a.x22*b.x20;res.x21=a.x20*b.x01+a.x21*b.x11+a.x22*b.x21;res.x22=a.x22*b.x22;return res;
}
Vec operator * (const Vec &a,const Matrix &b){Vec res;res.x00=a.x00*b.x00+a.x02*b.x20;res.x01=a.x00*b.x01+a.x01*b.x11+a.x02*b.x21;res.x02=a.x02*b.x22;return res;
}
Vec operator +(const Vec &a,const Vec &b){return {a.x00+b.x00,a.x01+b.x01,a.x02+b.x02,};
}
Matrix I={1,0,1,0,0,1};
Matrix C={1,1,1,0,0,1};
Matrix getA(int k){return Matrix{1,0,1,k,0,1};
}
vector<int> a,b;
struct SegmentTree{struct Node{Vec v;Matrix tag=I;bool lazy=0;};vector<Node> t;void init(int n){t=vector<Node>(n<<2);build(1,1,n);}void pushup(int p){t[p].v=t[p<<1].v+t[p<<1|1].v;}void pushtag(int p,const Matrix &m){t[p].v=t[p].v*m;t[p].tag=t[p].tag*m;t[p].lazy=1;}void pushdown(int p){if(t[p].lazy){pushtag(p<<1,t[p].tag);pushtag(p<<1|1,t[p].tag);t[p].lazy=0;t[p].tag=I;}}void build(int p,int l,int r){if(l==r){t[p].v={0,0,1};return;}int mid=l+r>>1;build(p<<1,l,mid);build(p<<1|1,mid+1,r);pushup(p);}void modify(int p,int l,int r,int ql,int qr,const Matrix &x){if(ql<=l&&r<=qr){pushtag(p,x);return;}pushdown(p);int mid=l+r>>1;if(ql<=mid)modify(p<<1,l,mid,ql,qr,x);if(qr>mid)modify(p<<1|1,mid+1,r,ql,qr,x);pushup(p);}int query(int p,int l,int r,int ql,int qr){if(ql<=l&&r<=qr)return t[p].v.x01;pushdown(p);int res=0,mid=l+r>>1;if(ql<=mid)res+=query(p<<1,l,mid,ql,qr);if(qr>mid)res+=query(p<<1|1,mid+1,r,ql,qr);return res;}
} t;
void solve(){int n,q;cin>>n>>q;vector<int> a(n+1);for(int i=1;i<=n;i++)cin>>a[i];vector<int> ans(q);vector<array<int,4>> Que[n+1];for(int i=0;i<q;i++){int l,r,L,R;cin>>l>>r>>L>>R;Que[R].push_back({l,r,i,1});Que[L-1].push_back({l,r,i,-1});}t.init(n);set<int> s={0};vector<int> pre(n+1);for(int i=1;i<=n;i++){if(pre[a[i]]){auto j=s.lower_bound(pre[a[i]]);int l=*prev(j)+1,r=*j;int v=(next(j)==s.end())?i-*j:*next(j)-*j;// cout<<l<<" "<<r<<" "<<v<<"\n";t.modify(1,1,n,l,r,getA(v));s.erase(j);}t.modify(1,1,n,i,i,getA(i));pre[a[i]]=i;s.insert(i);t.modify(1,1,n,1,i,C);for(auto [l,r,id,op]:Que[i]){r=min(r,i);ans[id]+=op*t.query(1,1,n,l,r);}}for(int i=0;i<q;i++)cout<<ans[i]<<"\n";
}

P9990/2020 ICPC EcFinal G

在這里插入圖片描述

#include<bits/stdc++.h>
#define N 1000005
#define rd read()
#define int long long
using namespace std;
int n,m,p[N],a[N],ans[N],t,l,r,op,las[N];
vector<pair<int,int> >q[N]; 
stack<int>s;
inline int read()
{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;
}
struct ver{int x11,x21,x31;ver operator + (const ver &o){return {x11+o.x11,x21+o.x21,x31+o.x31};}
}tr[N<<2];
struct mat{int x11,x12;int x21,x22;int x31,x32;mat operator * (const mat &o){mat res;res.x11=x11*o.x11+x12*o.x21;res.x12=x11*o.x12+x12*o.x22;res.x21=x21*o.x11+x22*o.x21;res.x22=x21*o.x12+x22*o.x22;res.x31=x31*o.x11+x32*o.x21+o.x31;res.x32=x31*o.x12+x32*o.x22+o.x32;return res;}ver operator * (const ver &o){return {x11*o.x11+x12*o.x21,x21*o.x11+x22*o.x21,x31*o.x11+x32*o.x21+o.x31};}
}tag[N<<2];
inline void pushup(int k){tr[k]=tr[k<<1]+tr[k<<1|1];}
inline void build(int k,int l,int r){tag[k]={1,0,0,1,0,0};if(l==r){return tr[k].x21=1,void();}int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);pushup(k);
}
inline void add(int k,mat v){tag[k]=v*tag[k];tr[k]=v*tr[k];
}
inline void pushdown(int k){add(k<<1,tag[k]);add(k<<1|1,tag[k]);tag[k]={1,0,0,1,0,0};
}
inline void modify(int k,int l,int r,int x,int y,mat v){if(x<=l&&r<=y){return add(k,v),void();}int mid=l+r>>1;pushdown(k);if(x<=mid) modify(k<<1,l,mid,x,y,v);if(y>mid) modify(k<<1|1,mid+1,r,x,y,v);pushup(k);
}
inline ver query(int k,int l,int r,int x,int y){if(x<=l&&r<=y){return tr[k];}int mid=l+r>>1;ver res={0,0,0};pushdown(k);if(x<=mid) res=res+query(k<<1,l,mid,x,y);if(y>mid) res=res+query(k<<1|1,mid+1,r,x,y);return res;
}
signed main(){n=rd;build(1,1,n);for(int i=1;i<=n;i++) a[i]=rd;m=rd;for(int i=1;i<=m;i++) l=rd,r=rd,q[r].push_back({i,l});for(int i=1;i<=n;i++){modify(1,1,n,las[a[i]]+1,i,{0,1,1,0,0,0});modify(1,1,n,1,n,{1,0,0,1,1,0});las[a[i]]=i;for(auto [id,l]:q[i]) ans[id]=query(1,1,n,l,i).x31;}for(int i=1;i<=m;i++) cout<<ans[i]<<'\n';return 0;
}	

拿CF ECFinal的數據測試
在這里插入圖片描述
從上到下分別是改良后的矩陣乘法(即本文章使用的),多重標記,矩陣乘法未減少狀態,以及兩個普通矩陣乘法

可以看到優化還是很明顯的,比賽的時候時間充足找不到打多重標記的做法可以使用,優點就是非常套路,缺點就是代碼量會大一點,并且非常難調(幾個初始矩陣一定要用對)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/83899.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/83899.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/83899.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

RabbitMQ入門4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年開發&#xff0c;后來由Pivotal Software Inc.&#xff08;現為VMware子公司&#xff09;接管。RabbitMQ 是一個開源的消息代理和隊列服務器&#xff0c;用 Erlang 語言編寫。廣泛應用于各種分布…

Python Copilot【代碼輔助工具】 簡介

粉絲愛買鱈魚腸深海鱈魚肉魚肉香腸盼盼麥香雞味塊卡樂比&#xff08;Calbee&#xff09;薯條三兄弟 獨立小包美麗雅 奶茶杯一次性飲料杯好時kisses多口味巧克力糖老金磨方【黑金系列】黑芝麻丸鄭新初網紅鄭新初烤鮮牛肉干超人毛球修剪器去球器剃毛器衣服去毛器優惠券寧之春 紅黑…

VBA進度條ProgressForm1

上一章《VBA如何使用ProgressBar進度條控件》介紹了ProgressBar控件的使用方法&#xff0c;今天我給大家介紹ProgressForm1進度條的使用方法&#xff0c;ProgressForm1是集成ProgressBar控件和Label控件的窗體&#xff0c;可以同時顯示進度條和百分比&#xff0c;如下圖&#x…

快速部署和啟動Vue3項目

快速入門Vue3 一、安裝 Node.js 和 npm Vue 3 是基于 JavaScript 的框架&#xff0c;Node.js 提供了 JavaScript 運行環境&#xff0c;npm 是 Node.js 的包管理工具&#xff0c;用于安裝和管理 Vue 3 及相關依賴。訪問 Node.js 官方網站&#xff08;https://nodejs.org/&…

[TIP] Ubuntu 22.04 配置多個版本的 GCC 環境

問題背景 在 Ubuntu 22.04 中安裝 VMware 虛擬機時&#xff0c;提示缺少 VMMON 和 VMNET 模塊 編譯這兩個模塊需要 GCC 的版本大于 12.3.0&#xff0c;而 Ubuntu 22.04 自帶的 GCC 版本為 11.4.0 因此需要安裝對應的 GCC 版本&#xff0c;但為了不影響其他程序&#xff0c;需…

【西門子杯工業嵌入式-4-什么是外部中斷】

西門子杯工業嵌入式-4-什么是外部中斷 一、中斷的基本概念1. 什么是中斷2. 生活中的中斷示例3. MCU 中的中斷機制 二、NVIC 嵌套向量中斷控制器1. NVIC 簡介2. NVIC 的作用3. 中斷向量表 三、中斷優先級機制1. 中斷優先級的含義2. 搶占與響應優先級3. 優先級分組配置 四、外部中…

Blocked aria-hidden on an element because its descendant retained focus.

問題出在 Element UI 的 el-table 組件 全選功能上&#xff0c;這是一個常見的無障礙&#xff08;a11y&#xff09;問題。這個錯誤提示與網頁 accessibility&#xff08;無障礙訪問&#xff09;相關&#xff0c;涉及 aria-hidden 屬性的不當使用。 問題原因分析 1. Element U…

App/uni-app 離線本地存儲方案有哪些?最推薦的是哪種方案?

以下是 UniApp 離線本地存儲方案的詳細介紹及推薦方案分析&#xff1a; 一、UniApp 離線本地存儲方案分類 1. 基于 uni.storage 系列 API&#xff08;跨端基礎方案&#xff09; API 及特點&#xff1a; 提供 uni.setStorage&#xff08;異步存儲&#xff09;、uni.getStorag…

數據庫系統概論(十七)超詳細講解數據庫規范化與五大范式(從函數依賴到多值依賴,再到五大范式,附帶例題,表格,知識圖譜對比帶你一步步掌握)

數據庫系統概論&#xff08;十七&#xff09;超詳細講解數據庫規范化與五大范式&#xff08;從函數依賴到多值依賴&#xff0c;再到五大范式&#xff0c;附帶例題&#xff0c;表格&#xff0c;知識圖譜對比帶你一步步掌握&#xff09; 前言一、為什么需要規范化1. 我們先想一個…

交互標牌——視覺貨幣(數字)轉換器項目及源碼

一、作品簡介 視覺貨幣&#xff08;數字&#xff09;轉換器是我為交互標牌創客爭霸賽設計的項目&#xff0c;項目的主要功能是能將所見的數字按照設定的公式轉換成新的單位量&#xff0c;這里我主要演示的是貨幣轉換&#xff0c;直接將攝像頭對準價簽&#xff0c;即可顯示出轉換…

React 第五十四節 Router中useRevalidator的使用詳解及案例分析

前言 useRevalidator 是 React Router v6.4 引入的一個強大鉤子&#xff0c;用于在數據路由&#xff08;Data Router&#xff09;中手動觸發路由數據的重新驗證&#xff08;revalidation&#xff09;。 它在需要主動刷新數據而不改變路由位置的場景中非常有用。 一、useReval…

“一代更比一代強”:現代 RAG 架構的演進之路

編者按&#xff1a; 我們今天為大家帶來的文章&#xff0c;作者的觀點是&#xff1a;RAG 技術的演進是一個從簡單到復雜、從 Naive 到 Agentic 的系統性優化過程&#xff0c;每一次優化都是在試圖解決無數企業落地大語言模型應用時出現的痛點問題。 文章首先剖析 Naive RAG 的基…

Flask-SQLAlchemy使用小結

鏈表查詢 join方法允許你指定兩個或多個表之間的連接條件&#xff0c;并返回一個新的查詢對象&#xff0c;該對象包含了連接后的結果。 內連接 from sqlalchemy import join # 使用join函數 query db.session.query(User, Order).join(Order, User.id Order.user_id) res…

【python與生活】如何構建一個解讀IPO招股書的算法?

構建一個基于Python的IPO招股書解讀算法需要結合自然語言處理&#xff08;NLP&#xff09;技術和大型語言模型&#xff08;LLM&#xff09;。以下是一個完整的解決方案&#xff0c;使用LangChain框架和OpenAI的GPT模型&#xff1a; import os import re import pandas as pd f…

LangChain面試內容整理-知識點1:LangChain架構與核心理念

LangChain 是一個用于構建基于大型語言模型(LLM)的應用的框架,其架構采用模塊化設計,核心理念是將語言模型與外部工具、數據源相結合,以實現復雜任務的分解與執行medium.com。整個框架可以理解為一系列可組合的組件,包括鏈(Chain)、智能體(Agent)、工具(Tool)和LLM…

13.MySQL用戶管理

13.MySQL用戶管理 目錄 MySQL用戶管理 用戶 用戶信息創建用戶修改用戶密碼刪除用戶 數據庫的權限 MySQL中的權限給用戶授權回收權限 用戶 用戶信息 MySQL中的用戶信息存儲在默認數據庫mysql的user表中。這個表記錄了所有用戶的詳細信息&#xff0c;包括用戶名、登錄權限…

分布式Session處理的五大主流方案解析

在分布式環境下&#xff0c;Session 處理的核心挑戰是確保用戶請求在不同服務器間流轉時能保持會話狀態一致。以下是主流解決方案及優缺點分析&#xff1a; &#x1f510; 一、集中存儲方案&#xff08;主流推薦&#xff09; Redis/Memcached 存儲 原理&#xff1a;將 Session…

【數據分析】什么是魯棒性?

引言 —— 為什么我們需要“抗折騰”的系統&#xff1f; 當你乘坐的飛機穿越雷暴區時機體劇烈顛簸&#xff0c;自動駕駛汽車在暴雨中穩穩避開障礙物&#xff0c;或是手機從口袋摔落后依然流暢運行——這些場景背后&#xff0c;都藏著一個工程領域的“隱形守護者”&#xff1a;…

altium designer2024繪制stm32過程筆記x`

學習視頻&#xff1a;【Altium Designer 1小時&#xff08;貌似不夠&#xff09;速成&#xff08;可能不止一小時*~* 但我覺得仨小時肯定夠了---來自up豬的自信!!&#xff09;】https://www.bilibili.com/video/BV17E411x7dR?p2&vd_sourcea756421e0aaa64b2bba352eabfa26ed…

Java 類型參數 T、R 、 O 、K、V 、E 、? 區別

在 Java 泛型和函數式編程中&#xff0c;T、R 和 O 都是類型參數&#xff08;Type Parameters&#xff09;&#xff0c;它們的主要區別在于命名約定和上下文含義&#xff0c;而不是語言層面的區別。它們可以互換使用&#xff0c;但通常遵循一定的命名習慣以提高代碼可讀性。 1.…