省選模擬25
阿新 • • 發佈:2022-03-04
字首 斐波那契 過路費
A. 字首
\(kmp\) 跑一下就能統計字首的出現次數
Code
#include<bits/stdc++.h> #define int long long//OVERFLOW !!! MEMORY LIMIT !!! #define rint signed #define inf 0x3f3f3f3f3f3f3f3f using namespace std; 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<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } int n,ans; int kmp[10000010]; int sum[10000010]; char st[10000010]; signed main(){ #ifdef LOCAL freopen("in","r",stdin); freopen("out","w",stdout); #endif freopen("pre.in","r",stdin); freopen("pre.out","w",stdout); scanf("%s",st+1);n=strlen(st+1); for(int i=2,j=0;i<=n;i++){ while(j&&st[j+1]!=st[i]) j=kmp[j]; if(st[j+1]==st[i]) j++;kmp[i]=j; } for(int i=1,j;i<=n;i++){j=i;sum[i]=sum[kmp[i]]+1;ans+=sum[i];} printf("%lld\n",ans); return 0; }
B. 斐波那契
用矩陣求斐波那契數列,再用線段樹維護一下就行
Code
#include<bits/stdc++.h> #define int long long//OVERFLOW !!! MEMORY LIMIT !!! #define rint signed #define lson rt<<1 #define rson rt<<1|1 #define mod 1004535809 #define inf 0x3f3f3f3f3f3f3f3f using namespace std; 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<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } int n,m; int a[100010]; struct mat{ int a[2][2]; inline mat operator*(const mat &b)const{ mat c; (c.a[0][0]=a[0][0]*b.a[0][0]+a[0][1]*b.a[1][0])%=mod; (c.a[0][1]=a[0][0]*b.a[0][1]+a[0][1]*b.a[1][1])%=mod; (c.a[1][0]=a[1][0]*b.a[0][0]+a[1][1]*b.a[1][0])%=mod; (c.a[1][1]=a[1][0]*b.a[0][1]+a[1][1]*b.a[1][1])%=mod; return c; } }B,Bk,F,Fk,T; struct seg{mat sum;int atag;}st[100010*4]; inline void md(int &x){x=(x>=mod)?x-mod:x;} inline mat qpow(mat x,int k){ mat base,res;base=x;res.a[0][1]=res.a[1][0]=0;res.a[0][0]=res.a[1][1]=1; while(k){if(k&1) res=res*base;base=base*base;k>>=1;} return res; } inline void pushup(int rt){ md(st[rt].sum.a[0][0]=st[lson].sum.a[0][0]+st[rson].sum.a[0][0]); md(st[rt].sum.a[0][1]=st[lson].sum.a[0][1]+st[rson].sum.a[0][1]); md(st[rt].sum.a[1][0]=st[lson].sum.a[1][0]+st[rson].sum.a[1][0]); md(st[rt].sum.a[1][1]=st[lson].sum.a[1][1]+st[rson].sum.a[1][1]); } inline void pushdown(int rt){ if(st[rt].atag){ st[lson].atag+=st[rt].atag; st[rson].atag+=st[rt].atag; Bk=qpow(B,st[rt].atag); st[lson].sum=Bk*st[lson].sum; st[rson].sum=Bk*st[rson].sum; st[rt].atag=0; } } void build(int rt,int l,int r){ if(l==r) return st[rt].sum=qpow(B,a[l]-1)*F,void(); int mid=(l+r)>>1; build(lson,l,mid); build(rson,mid+1,r); pushup(rt); } void upd(int rt,int l,int r,int L,int R,int k){ if(L<=l&&r<=R) return st[rt].sum=qpow(B,k)*st[rt].sum,st[rt].atag+=k,void(); int mid=(l+r)>>1;pushdown(rt); if(L<=mid) upd(lson,l,mid,L,R,k); if(R>mid) upd(rson,mid+1,r,L,R,k); pushup(rt); } int query(int rt,int l,int r,int L,int R){ if(L<=l&&r<=R) return st[rt].sum.a[0][0]; int mid=(l+r)>>1,res=0;pushdown(rt); if(L<=mid) md(res+=query(lson,l,mid,L,R)); if(R>mid) md(res+=query(rson,mid+1,r,L,R)); return res; } signed main(){ #ifdef LOCAL freopen("in","r",stdin); freopen("out","w",stdout); #endif freopen("fib.in","r",stdin); freopen("fib.out","w",stdout); B.a[0][0]=1,B.a[0][1]=1,B.a[1][0]=1,B.a[1][1]=0; F.a[0][0]=1,F.a[0][1]=0,F.a[1][0]=0,F.a[1][1]=0; n=read(),m=read();for(int i=1;i<=n;i++) a[i]=read(); build(1,1,n); for(int i=1,op,l,r;i<=m;i++){ op=read(),l=read(),r=read(); if(op==1) upd(1,1,n,l,r,read()); if(op==2) printf("%lld\n",query(1,1,n,l,r)); } return 0; }
C. 過路費
依次列舉每條邊的權值,給每條邊的權值都變成 \(x-w\) ,再和 \(0\) 取 \(\max\) ,其中 \(w\) 是列舉的權值
最後的答案就是 \(dis_T+k*w\) ,對所有的結果取 \(\min\)
考慮為啥這樣做是正確的
如果到 \(T\) 的最短路多於 \(k\) 條,那麼這條路徑在列舉的 \(w\) 更大時算出來的結果一定更小
如果少於 \(k\) 條,那這種情況的答案一定比在 \(w\) 小的時候算出來的要大
因為他把不到 \(w\) 的都補成了 \(w\)
Code
#include<bits/stdc++.h> #define int long long//OVERFLOW !!! MEMORY LIMIT !!! #define rint signed #define inf 0x3f3f3f3f3f3f3f3f using namespace std; 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<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } int n,m,k,S,T,ans; int dis[1010],num[1010]; int head[1010],ver[2010],edge[2010],to[2010],tot; bool vis[1010]; struct Edge{int x,y,z;}e[2010]; inline void add(int x,int y,int z){ver[++tot]=y;edge[tot]=z;to[tot]=head[x];head[x]=tot;} priority_queue<pair<int,int>>q; void dij(int X){ for(int i=1;i<=n;i++) dis[i]=inf,vis[i]=0,head[i]=0;tot=0; for(int i=1;i<=m;i++) add(e[i].x,e[i].y,max(e[i].z-X,0ll)); dis[S]=0;q.push(make_pair(0,S)); while(!q.empty()){ int x=q.top().second;q.pop();if(vis[x]) continue;vis[x]=1; for(int i=head[x];i;i=to[i]){ int y=ver[i]; if(dis[y]>dis[x]+edge[i]){ dis[y]=dis[x]+edge[i]; q.push(make_pair(-dis[y],y)); } } } ans=min(ans,dis[T]+X*k); } signed main(){ #ifdef LOCAL freopen("in","r",stdin); freopen("out","w",stdout); #endif freopen("fee.in","r",stdin); freopen("fee.out","w",stdout); n=read(),m=read(),k=read(),S=read(),T=read();ans=inf; for(int i=1;i<=m;i++) e[i].x=read(),e[i].y=read(),e[i].z=read(); for(int i=1;i<=m;i++) dij(e[i].z);dij(0); printf("%lld\n",ans); return 0; }