1. 程式人生 > 其它 >【考試總結】2022-03-04

【考試總結】2022-03-04

A.字首 B.斐波那契 C.過路費

字首

使用 \(ex-kmp\) 求出來每個字尾 和全串的 \(\rm LCP\) 長度,那麼對應 \(len\in[1,LCP]\) 的字首又出現了一次

Code Display
const int N=1e7+10;
int z[N],ans,ton[N],n;
char s[N];
signed main(){
    freopen("pre.in","r",stdin); freopen("pre.out","w",stdout);
    scanf("%s",s+1); n=strlen(s+1);
    z[1]=n;
    for(int i=2,l=0,r=0;i<=n;++i){
        if(i<=r) z[i]=min(z[i-l+1],r-i+1);
        while(i+z[i]<=n&&s[z[i]+1]==s[i+z[i]]) ++z[i];
        if(i+z[i]-1>r) l=i,r=i+z[i]-1;
    }
    for(int i=1;i<=n;++i) ton[z[i]]++;
    Down(i,n,1) ton[i]+=ton[i+1],ans+=ton[i];
    print(ans);
    return 0;
}

斐波那契

使用線段樹維護矩陣即可,每次區間加定值時可以乘一個對應次數的轉移矩陣

那麼區間求 \(\rm Fib\) 的和就對應區間矩陣的和

Code Display
const int N=1e5+10;
struct mat{
    int a[2][2]; mat(){a[0][0]=a[0][1]=a[1][0]=a[1][1]=0;}
    mat(int b,int c,int d,int e){a[0][0]=b; a[0][1]=c; a[1][0]=d; a[1][1]=e;}
    bool operator ==(const mat &e)const{
        rep(i,0,1) rep(j,0,1) if(a[i][j]!=e.a[i][j]) return 0;
        return 1;
    }
}pw[40],val[N<<2],tag[N<<2];
inline mat Mul(mat &a,mat &b){
    mat c;
    c.a[0][0]=add(mul(a.a[0][0],b.a[0][0]),mul(a.a[0][1],b.a[1][0]));
    c.a[0][1]=add(mul(a.a[0][0],b.a[0][1]),mul(a.a[0][1],b.a[1][1]));
    c.a[1][0]=add(mul(a.a[1][0],b.a[0][0]),mul(a.a[1][1],b.a[1][0]));
    c.a[1][1]=add(mul(a.a[1][0],b.a[0][1]),mul(a.a[1][1],b.a[1][1]));
    return c;
}
inline mat Plus(mat a,mat b){
    mat c;
    rep(i,0,1) rep(j,0,1) c.a[i][j]=add(a.a[i][j],b.a[i][j]);
    return c;
}
inline mat Minus(mat a,mat b){
    mat c;
    rep(i,0,1) rep(j,0,1) c.a[i][j]=del(a.a[i][j],b.a[i][j]);
    return c;
}
inline mat Get(int n){
    mat res=mat(1,0,0,1);
    for(int i=1;i<=32;++i) if(n>>(i-1)&1) res=Mul(res,pw[i]);
    return res;
}
int a[N],n,Q;
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
inline void push_tag(int p,mat now){
    val[p]=Mul(val[p],now);
    tag[p]=Mul(tag[p],now);
    return ;
}
inline void push_down(int p){
    if(tag[p]==pw[0]) return ;
    push_tag(ls,tag[p]); push_tag(rs,tag[p]);
    tag[p]=pw[0];
    return ;
}
inline void push_up(int p){val[p]=Plus(val[ls],val[rs]);}
inline void build(int p,int l,int r){
    tag[p]=pw[0]; if(l==r) return val[p]=Get(a[l]-1),void();
    int mid=(l+r)>>1; build(lson); build(rson);
    return push_up(p);
}
inline void upd(int st,int ed,mat d,int p=1,int l=1,int r=n){
    if(st<=l&&r<=ed) return push_tag(p,d); 
    int mid=(l+r)>>1; push_down(p);
    if(st<=mid) upd(st,ed,d,lson); if(ed>mid) upd(st,ed,d,rson);
    return push_up(p);
}
inline mat query(int st,int ed,int p=1,int l=1,int r=n){
    if(st<=l&&r<=ed) return val[p];
    int mid=(l+r)>>1; push_down(p);
    if(ed<=mid) return query(st,ed,lson);
    if(st>mid) return query(st,ed,rson);
    return Plus(query(st,ed,lson),query(st,ed,rson));
}
#undef ls
#undef rs
#undef lson
#undef rson
signed main(){
    freopen("fib.in","r",stdin); freopen("fib.out","w",stdout);
    n=read(); Q=read(); rep(i,1,n) a[i]=read();
    pw[0]=mat(1,0,0,1); pw[1]=mat(0,1,1,1);
    for(int i=2;i<=35;++i) pw[i]=Mul(pw[i-1],pw[i-1]);   
    build(1,1,n);

    while(Q--){
        if(read()-1){
            int l=read(),r=read();
            mat ans=query(l,r);
            print(add(ans.a[0][0],ans.a[1][0]));
        }else{
            int l=read(),r=read();
            upd(l,r,Get(read()));
        }
    }
    return 0;
}

過路費

考慮列舉最短路上作為第 \(k\) 大的邊的權值 \(v\),全圖的邊都減掉 \(v\)\(Dijkstra\) 將得數加 \(kv\) 即可

這樣做正確的原因是如果少於 \(k\) 條邊不小於 \(v\) 那麼必然附加的 \(kv\) 是冗餘的,而如果超過 \(k\) 條邊大於 \(v\) 那麼將 \(v\) 取更大的值時必然有更好的結果

Code Display
const int N=2010;
int S,T,n,m,k,b[N];
vector<pair<int,int> > G[N];
int dis[N];
int u[N],v[N],w[N];
inline void rebuild(int d){
    for(int i=1;i<=n;++i) G[i].clear();
    for(int i=1;i<=m;++i){
        G[u[i]].push_back({v[i],max(0ll,w[i]-d)});
    } return ;
}
bool vis[N];
signed main(){
    freopen("fee.in","r",stdin); freopen("fee.out","w",stdout);
    n=read(); m=read(); k=read(); S=read(); T=read();
    int cnt_val=0;
    for(int i=1;i<=m;++i){
        u[i]=read(); v[i]=read(); w[i]=read();
        b[++cnt_val]=w[i];
    }
    int ans=0x3f3f3f3f3f3f3f3f;
    sort(b+1,b+cnt_val+1); cnt_val=unique(b+1,b+cnt_val+1)-b-1;
    for(int p=1;p<=cnt_val;++p){
        rebuild(b[p]);
        memset(dis,0x3f,sizeof(dis));
        priority_queue<pair<int,int> >q; q.push({0,S}); dis[S]=0;
        rep(i,1,n) vis[i]=0;
        while(q.size()){
            int fr=q.top().sec; q.pop(); if(vis[fr]) continue; vis[fr]=1;
            for(auto e:G[fr]){
                if(dis[e.fir]>dis[fr]+e.sec){
                    dis[e.fir]=dis[fr]+e.sec;
                    q.push(make_pair(-dis[e.fir],e.fir));
                }
            } 
        }
        ckmin(ans,dis[T]+k*b[p]);
    } print(ans);
    return 0;
}

這套題目相信很多同學聯賽做和現在做得分並不會有什麼不同