省选模拟25
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;
}