省选模拟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;
}
posted @ 2022-03-04 14:20  Max_QAQ  阅读(49)  评论(0编辑  收藏  举报