1. 程式人生 > 其它 >省選模擬25

省選模擬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;
}