20181026小结

【模板】矩阵快速幂 2714
性感手枪 4145
简单题 2723
货车运输 1807
【模板】树状数组 区间修改区间求和 1685


【模板】矩阵快速幂 2714

矩阵乘法
快速幂
一个 n * p 的矩阵与一个 p * m 的矩阵,相乘得到一个 n * m 的矩阵

题解
f(1)=1;f(2)=1;f(n)=A f(n-1)+B f(n-2);
所以
在这里插入图片描述

矩阵乘法公式:A * B->C

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=30013;
struct Array{
	ll matrix[2][2];
}t,ans,temp;
ll a,b,k;
Array mul(Array a,Array b){
	Array res;
	memset(res.matrix,0,sizeof(res.matrix));
	for(ll i=0;i<2;i++)
		for(ll j=0;j<2;j++)
			for(ll k=0;k<2;k++){
				res.matrix[i][j]+=a.matrix[i][k]*b.matrix[k][j]%mod;
				res.matrix[i][j]%=mod;
			}
	return res;
}
Array maxtrix_ksm(Array a,ll b){
	Array res,temp;
	memset(res.matrix,0,sizeof(res.matrix));
	for(ll i=0;i<2;i++)
		res.matrix[i][i]=1;
	temp=a;
	while(b){
		if(b&1)res=mul(res,temp);
		temp=mul(temp,temp);
		b>>=1;
	}
	return res;
}
int main(){
	memset(t.matrix,0,sizeof(t.matrix));
	cin>>a>>b;
	ans.matrix[0][0]=ans.matrix[0][1]=1;
	t.matrix[0][0]=a;t.matrix[0][1]=1;
	t.matrix[1][0]=b;t.matrix[1][1]=0;
	cin>>k;
	if(k==1||k==2){
		cout<<ans.matrix[0][k-1];
		return 0;
	}
	temp=maxtrix_ksm(t,k-2);
	ans=mul(ans,temp);
	cout<<ans.matrix[0][0];
	return 0;
}

性感手枪 4145

%%%
DFS

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
bool a[1510][1510];
int vis[1510][1510][3];//x坐标    y坐标    是否访问 
int n,m,sx,sy,ans,t;
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
void dfs(int x,int y,int px,int py){//小矩阵中的坐标    大矩阵中的坐标 
	if(ans)return;
	if(vis[px][py][2]&&(vis[px][py][0]!=x||vis[px][py][1]!=y)){
		ans=1;return;//再次访问某个节点,但已是另一个复制的周边矩阵里的 
    }
	if(vis[px][py][2]&&vis[px][py][0]==x&&vis[px][py][1]==y)return;
    vis[px][py][0]=x;vis[px][py][1]=y;vis[px][py][2]=1;
    int xx,yy;
    for (int i=0;i<4;i++){
        xx=(px+dx[i]+n)%n;yy=(py+dy[i]+m)%m;    
        if (a[xx][yy])dfs(x+dx[i],y+dy[i],xx,yy);
    }
}
char c;
int main(){
	t=read();
	while(t--){
		memset(a,false,sizeof(a));
        memset(vis,false,sizeof(vis));
        ans=0;
		n=read();m=read();
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++){
				c=getchar();
				while(c!='S'&&c!='.'&&c!='#')c=getchar();
				if(c=='S'){
					sx=i;sy=j;a[i][j]=1;
				}
				if(c=='.')a[i][j]=1;
				if(c=='#')a[i][j]=0;
			}
		dfs(sx,sy,sx,sy);
		if(ans)printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}

简单题 2723

kruskal
最小瓶颈路
倍增
最小瓶颈路,是指两点之间所有路径中最大的边最小的路径(路径由边组成)
先构造一棵kruskal最小生成树,那么最小瓶颈路必然在这棵生成树上面。
对于每一对点,我们可以像找LCA一样找到最大值。

#include<bits/stdc++.h>
using namespace std;
struct edge{
	int u,v,w,nxt;
}e[100010],a[100010];
int first[10010],cnt=0;
inline void add(int u,int v,int w){
	a[++cnt].v=v;a[cnt].w=w;
	a[cnt].nxt=first[u];first[u]=cnt;
}
inline int Sort_5(edge x,edge y){
	return x.w<y.w;
}
int n,m,fa[10010][22],q;
inline int find(int x){
	if(x==fa[x][0])return x;
	return fa[x][0]=find(fa[x][0]);
}
int dep[10010],mx[10010][22];
void prework(int x,int f){
	fa[x][0]=f;
	dep[x]=dep[f]+1;
	for(int i=1;(1<<i)<=dep[x];i++){
		fa[x][i]=fa[fa[x][i-1]][i-1];
		mx[x][i]=max(mx[fa[x][i-1]][i-1],mx[x][i-1]);
	}
	for(int i=first[x];i;i=a[i].nxt){
		int v=a[i].v;
		if(v==f)continue;
		mx[v][0]=a[i].w;
		prework(v,x);
	}
}
int ask(int u,int v){
	if(dep[u]<dep[v])swap(u,v);
	int t=dep[u]-dep[v],ans=0;
	for(int i=0;i<=21;i++)
		if(t&(1<<i)){
			ans=max(ans,mx[u][i]);
			u=fa[u][i];
		}
	if(u==v)return ans;
	for(int i=21;i>=0;i--)
		if(fa[u][i]!=fa[v][i]){
			ans=max(ans,max(mx[u][i],mx[v][i]));
			u=fa[u][i];v=fa[v][i];
		}
	return max(ans,max(mx[u][0],mx[v][0]));
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)fa[i][0]=i;
	for(int i=1;i<=m;i++){
		int u,v,w;
		scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
	}
	sort(e+1,e+m+1,Sort_5);
	for(int i=1;i<=m;i++){
		int u=e[i].u,v=e[i].v;
		int fu=find(u),fv=find(v);
		if(fu==fv)continue;
		fa[fu][0]=fv;
		add(fu,fv,e[i].w);add(fv,fu,e[i].w);
	}
	memset(fa,0,sizeof(fa));
	prework(1,0);
	scanf("%d",&q);
	while(q--){
		int u,v;
		scanf("%d%d",&u,&v);
		printf("%d\n",ask(u,v));
	}
	return 0;
}

货车运输 1807

kruskal
最小瓶颈路
倍增
和上面一样,只不过是最大瓶颈路。

#include<bits/stdc++.h>
using namespace std;
struct edge{
	int u,v,w,nxt;
}e[100010],a[100010];
int first[10010],cnt=0;
inline void add(int u,int v,int w){
	a[++cnt].v=v;a[cnt].w=w;
	a[cnt].nxt=first[u];first[u]=cnt;
}
inline int Sort_5(edge x,edge y){
	return x.w>y.w;
}
int n,m,fa[10010][22],q,anc[10010];
inline int find(int x){
	if(x==anc[x])return x;
	return anc[x]=find(anc[x]);
}
int dep[10010],mn[10010][22];
void prework(int x,int f){
	fa[x][0]=f;
	dep[x]=dep[f]+1;
	for(int i=1;(1<<i)<=dep[x];i++){
		fa[x][i]=fa[fa[x][i-1]][i-1];
		mn[x][i]=min(mn[fa[x][i-1]][i-1],mn[x][i-1]);
	}
	for(int i=first[x];i;i=a[i].nxt){
		int v=a[i].v;
		if(v==f)continue;
		mn[v][0]=a[i].w;
		prework(v,x);
	}
}
int ask(int u,int v){
	if(dep[u]<dep[v])swap(u,v);
	int t=dep[u]-dep[v],ans=2000000000;
	for(int i=0;i<=21;i++)
		if(t&(1<<i)){
			ans=min(ans,mn[u][i]);
			u=fa[u][i];
		}
	if(u==v)return ans;
	for(int i=21;i>=0;i--)
		if(fa[u][i]!=fa[v][i]){
			ans=min(ans,min(mn[u][i],mn[v][i]));
			u=fa[u][i];v=fa[v][i];
		}
	return min(ans,min(mn[u][0],mn[v][0]));
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)anc[i]=i;
	for(int i=1;i<=m;i++){
		int u,v,w;
		scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
	}
	sort(e+1,e+m+1,Sort_5);
	for(int i=1;i<=m;i++){
		int u=e[i].u,v=e[i].v;
		int fu=find(u),fv=find(v);
		if(fu==fv)continue;
		anc[fu]=fv;
		add(fu,fv,e[i].w);add(fv,fu,e[i].w);
	}
	memset(mn,0x3f,sizeof(mn));
	for(int i=1;i<=n;i++)
		if(!dep[i]){//可能不连通 
			dep[i]=1;
			prework(i,0);
		}
	scanf("%d",&q);
	while(q--){
		int u,v;
		scanf("%d%d",&u,&v);
		if(find(u)!=find(v)){
			printf("-1\n");
			continue;
		}
		printf("%d\n",ask(u,v));
	}
	return 0;
}

【模板】树状数组 区间修改区间求和 1685

树状数组
xxxly%%%

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m;
struct BIT{
	ll t[400010]={0};
	void add(int x,ll v){
		for(;x<=n;x+=x&-x)t[x]+=v;
	}
	ll ask(int x){
		ll ans=0;
		for(;x;x-=x&-x)ans+=t[x];
		return ans;
	}
}c1,c2;
ll a[100010];
ll ans;
int main(){
//	freopen("1.in","r",stdin);
	scanf("%d%d",&n,&m);
	 int e,f,c;
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		c1.add(i,a[i]-a[i-1]);
		c2.add(i,(i-1)*1ll*(a[i]-a[i-1]));
	}
	while(m--){
		scanf("%d%d%d",&c,&e,&f);
		if(c==1){//区间加 
			scanf("%d",&c);
			c1.add(e,c);c1.add(f+1,-c);
			c2.add(e,(e-1)*c);c2.add(f+1,-f*c); 
		}
		else{//区间求和 
			ans=f*c1.ask(f)-c2.ask(f);
			ans-=(e-1)*c1.ask(e-1)-c2.ask(e-1);
			printf("%lld\n",ans);
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值