排位赛(6)继续“发愤”补题

A

题面:

请添加图片描述
请添加图片描述

题目大意:

请添加图片描述

思路

想直接算的话,直接暴毙O(∩_∩)O哈哈~
数据范围达到10^15。
请添加图片描述

一个线性递推式,递推到很大的某一项,祭出:矩阵快速幂!
请添加图片描述

AC代码

#include<bits/stdc++.h>
#define pb push_back
#define lowbit(x) x&(-x)
#define mst(a,b) memset(a,b,sizeof a)
#define fi first
#define se second
#define mp make_pair

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
const int Mod = 1e6;
const int N = 1e5+10;

ll Read(){
	ll val = 0, opt = 1; char ch;
	while (!isdigit(ch = getchar())) if (ch == '-') opt = -1;
	while (isdigit( ch )) (val *= 10) += ch - '0', ch = getchar();
	return val * opt;
}

struct mat{
	int n;
	vector<vector<long long> > val;
	
	//构造函数 
	explicit mat(int sz) : val(sz,vector<long long>(sz)){
		n=sz;
	}
	
	//单位矩阵 
	void emat(){
		for(int i=0;i<n;i++){
			for(int j=0;j<n;j++){
				val[i][j]= (i==j);
			}
		}
	}
	
	//重载乘号
	mat operator * (const mat &a) const{
		mat res(n);
		for(int i=0;i<n;i++){
			for(int j=0;j<n;j++){
				for(int k=0;k<n;k++){
					res.val[i][j]=(res.val[i][j]+val[i][k]*a.val[k][j])%Mod;
				}
			}
		}
		return res;
	} 
}; 

//快速幂
mat matqp(mat a,long long b){
	mat res(a.n);
	res.emat();
	while(b){
		if(b&1) res=res*a;
		a=a*a;
		b>>=1;
	}
	return res;
}

signed main(){
	ios::sync_with_stdio(false);
	
	ll n,k,l;
	cin>>n>>k>>l;
	n/=5;
	k%=Mod;l%=Mod;
	
	mat tran(2);
	tran.val[0][0]=k;tran.val[0][1]=l;
	tran.val[1][0]=1;tran.val[1][1]=0;
	mat res = matqp(tran, n-1);
	
	ll ans = (res.val[1][0])*(k*k+l)+(res.val[1][1])*k;
	ans%=Mod;
	printf("%06d\n", (int)ans);
    return 0;
}

J

题目

请添加图片描述

请添加图片描述
请添加图片描述

题目大意

给定一个有边权的连通图,求询问任意两点之间路径的最小边权的最大值。

思路

看到题面我立马想到了最大流,并很快反应过来自己不会最大流,现在也不会,无法讲出一个所以然(/ω\)
听了讲评之后,发现跟前一场补的题特别像,但是这场之后才补的题,,,这逻辑
1、容易发现所有经过的路径应该包含在一棵最大生成树中,用kruskal简化图。
2、询问两点的路径上的最小边权,答案是确定的,可该如何计算?
用LCA的思想,在倍增的过程中维护树上区间的最小值。

f[j][i+1] = f[ f[j][i] ][i];
mx[j][i+1] = min(mx[j][i], mx[ f[j][i] ][i]);

另解:

这题还可以用启发式合并(dsu),将询问绑到点上,将边从大到小加入并查集。合并的时候,若小集合中有和大集合相同的询问,则可以以当前加入的边的边权w回答该询问。

AC代码

#include<bits/stdc++.h>
#define pb push_back
#define lowbit(x) x&(-x)
#define mst(a,b) memset(a,b,sizeof a)
#define fi first
#define se second
#define mp make_pair

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
const int Mod = 1e9+7;
const int N = 1e5+10;

ll Read(){
	ll val = 0, opt = 1; char ch;
	while (!isdigit(ch = getchar())) if (ch == '-') opt = -1;
	while (isdigit( ch )) (val *= 10) += ch - '0', ch = getchar();
	return val * opt;
}

struct node{
	int st,ed,w;
}edge[N];

int fa[N];
int n,m,s;
vector<pair<int, int> > v[N];
int mx[N][30],f[N][30];
int dep[N];

bool cmp(node a,node b){
	return a.w > b.w;
} 

int Find(int x){
	if(x == fa[x]) return x;
	else return fa[x] = Find(fa[x]);
}

void ini(){
	for(int i=1;i<=n;i++) fa[i]=i;
	mst(dep, 0);
	mst(mx, INF);
	mst(f, -1);
}

void Union(int x, int y,int w){
	int f1 = Find(x);
	int f2 = Find(y);
	if(f1 != f2){
		fa[f1] = fa[f2];
		v[f1].pb(mp(f2, w));
		v[f2].pb(mp(f1, w));
	}
} 

void dfs(int u, int fa){
	dep[u] = dep[fa] + 1;
	f[u][0] = fa;
	
	for(auto i : v[u]){
		if(i.fi == fa) continue;
		
		mx[i.fi][0] = i.se;
		
		dfs(i.fi, u);	
	} 
}

int LCA(int x,int y){
	
	int ans = INF;
	
	if(dep[x] < dep[y]) swap(x,y);
	
	for(int i=25;i>=0;i--){
		if(f[x][i] != -1 && dep[ f[x][i] ] >= dep[y]){
			ans = min(ans, mx[x][i]);	//跳跃则更新答案 
			x = f[x][i];
		}
		if(x == y) return ans;
	}
	
	for(int i=25;i>=0;i--)
	{
		if(f[x][i] != f[y][i]){
			ans = min(ans, mx[x][i]);
			ans = min(ans, mx[y][i]);
			x=f[x][i];y=f[y][i];
		} 
	}
	ans = min(ans, mx[x][0]);
	ans = min(ans, mx[y][0]);
	return ans;
}

signed main(){
//	printf("%d", INF);
	
	n=Read();m=Read();s=Read();
	ini();
	
	for(int i=0;i<m;i++){
		edge[i].st=Read();
		edge[i].ed=Read();
		edge[i].w=Read();
	}
	
	sort(edge, edge + m, cmp);
	
	//保存最大生成树 
	for(int i=0;i<m;i++) Union(edge[i].st, edge[i].ed, edge[i].w);
	
	dfs(1,0);
	
	for(int i=0;i<30;i++){
		for(int j=1;j<=n;j++){
			if(f[j][i] != -1){
				f[j][i+1] = f[ f[j][i] ][i];
				mx[j][i+1] = min(mx[j][i], mx[ f[j][i] ][i]);
			}
		} 
	}
	
	while(s--){
		int a,b;
		a=Read();b=Read();
		cout<<LCA(a, b)<<endl;
	} 
    return 0;
}

另解

#include<bits/stdc++.h>
#define pb push
#define lowbit(x) x&(-x)
#define mst(a,b) memset(a,b,sizeof a)
#define fi first
#define se second
#define mp make_pair

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
const int Mod = 1e9+7;
const int N = 1e5+10;

ll Read(){
	ll val = 0, opt = 1; char ch;
	while (!isdigit(ch = getchar())) if (ch == '-') opt = -1;
	while (isdigit( ch )) (val *= 10) += ch - '0', ch = getchar();
	return val * opt;
}

pair<int, int> e[N];					//存边的始终点 
priority_queue<pair<int, int> > pq;		//存边权和边序号 
int fa[N];
set<int> re[N];							//询问集合 
int ans[N]; 

int Find(int u){
	if(u == fa[u]) return u;
	else return fa[u] = Find(fa[u]);
}

signed main(){
	int n,m,q;
	n=Read();m=Read();q=Read();
	
	int st,ed,w;
	for(int i=1;i<=m;i++){
		st=Read();ed=Read();w=Read();
		e[i].fi=st;
		e[i].se=ed;
		pq.pb(mp(w, i));
	}
	
	for(int i=1;i<=q;i++){
		st=Read();ed=Read();
		re[st].emplace(i);
		re[ed].emplace(i);	
	} 
	
	for(int i=1;i<=n;i++) fa[i]=i;
	
	int cnt=0;
	while(!pq.empty() && q > cnt){
		pair<int, int> p = pq.top();pq.pop();
		
		int f1=Find(e[p.se].fi),f2=Find(e[p.se].se);
		if(f1 == f2) continue;
		
		if(re[f1].size() > re[f2].size()) swap(f1, f2);
		
		//将f1并入f2
		fa[f1] = f2;
		
		for(auto i : re[f1]){
			if(re[f2].find(i) != re[f2].end()){
				ans[i] = p.fi;
				re[f2].erase(i);
				cnt++; //回答数+1 
			}
			else{
				re[f2].emplace(i);
			}
		} 
		re[f1].clear();
	}
	
	for(int i=1;i<=q;i++) printf("%d\n", ans[i]);
	
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

u小鬼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值