2019.9.7 模拟测试

T1 矩形

这是一道防AK题(确信)反正我被防了(是个辣鸡)

vanvan没想到还能斜着放,我说第一题怎么能这么简单

很巧妙的方法就是将一个矩形的对角线放在另一个矩形中再判断高度差即可

#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;

int n;
double a1,a2,b1,b2;

int main(){
	cin>>n;
	for(int i=1;i<=n;++i){
		scanf("%lf%lf%lf%lf",&a1,&b1,&a2,&b2);
		if(a1>b1)  swap(a1,b1);
		if(a2>b2)  swap(a2,b2);
		if(a1*b1>a2*b2)  swap(a1,a2),swap(b1,b2);
		if(a1<=a2&&b1<=b2){puts("Yes");continue;}
		else{
			double r1=a1*a1+b1*b1,r2=a2*a2+b2*b2;
			if(r1>r2){puts("No");continue;}
			else{
				r1=sqrt(r1-b2*b2);
				double p=(2.0*b2*a1*b1+b1*b1*r1-a1*a1*r1)/(a1*a1+b1*b1);
				if(p-a2<eps)  puts("Yes");
				else  puts("No");
			}
		}
	}
	return 0;
}

T2 最短路

首先删边不好想,反向加边即可。

既然删边操作不会超过200次,那么完全可以接受每插入一条边就更新所有以修改点为中转点的路径,复杂度O(n^3)

(差点打挂Floyd)

#include<bits/stdc++.h>
using namespace std;
const int MAXN=210;
const int MAXM=1e5+10;
const int INF=0x3f3f3f3f;

int n,m,now;
int ma[MAXN][MAXN],ans[MAXM],top;
int dis[MAXN][MAXN],ban[MAXN][MAXN];
struct Q{
	int type;
	int x,y;
}query[MAXM];

int Read(){
	int i=0,f=1;
	char c=getchar();
	for(;(c>'9'||c<'0')&&c!='-';c=getchar());
	if(c=='-')  f=-1,c=getchar();
	for(;c>='0'&&c<='9';c=getchar())  i=(i<<3)+(i<<1)+c-'0';
	return i*f;
}

int main(){
	n=Read(),m=Read();
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			ma[i][j]=Read();
		}
	}
	for(int i=1;i<=m;++i){
		query[i].type=Read(),query[i].x=Read(),query[i].y=Read();
		if(query[i].type==1)  ban[query[i].x][query[i].y]=1;
	}
	memset(dis,INF,sizeof(dis));
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j)  if(!ban[i][j])  dis[i][j]=min(dis[i][j],ma[i][j]);
	}
	for(int k=1;k<=n;++k){
		for(int i=1;i<=n;++i){
			for(int j=1;j<=n;++j){
				if(dis[i][k]+dis[k][j]<dis[i][j])  dis[i][j]=dis[i][k]+dis[k][j];
			}
		}
	}
	for(int i=m;i;--i){
		if(query[i].type==2)  ans[++top]=(dis[query[i].x][query[i].y])==INF?-1:dis[query[i].x][query[i].y];
		else{
			if(ma[query[i].x][query[i].y]>=dis[query[i].x][query[i].y])  continue;
			dis[query[i].x][query[i].y]=ma[query[i].x][query[i].y];
			for(int j=1;j<=n;++j){
				for(int k=1;k<=n;++k){
					if(dis[query[i].x][j]+dis[j][k]<dis[query[i].x][k])  dis[query[i].x][k]=dis[query[i].x][j]+dis[j][k];
				}
			}
			for(int j=1;j<=n;++j){
				for(int k=1;k<=n;++k){
					if(dis[j][query[i].x]+dis[query[i].x][k]<dis[j][k])  dis[j][k]=dis[j][query[i].x]+dis[query[i].x][k];
				}
			}
		}
//		solve(query[i].x,query[i].y);
	}
	for(int i=top;i;--i)  cout<<ans[i]<<'\n';
}

T3 集合

好像有树形DP的优秀O(n)做法?我太菜了不会啊

首先易证两个集合点一定有一个在直径上,那么我们可以直接二分距离,从直径两端向中间跳二分出的mid个,然后检查两个集合点之间的点到最近集合点加上非直径最长链长度是否不大于二分出的距离即可

dfs本机爆栈于是愉快的写了bfs

#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+10;
const int MAXM=4e5+10;

int n,cnt;
int maxx,s,t,ss,tt;
int head[MAXN],vis[MAXN],viss[MAXN],on[MAXN],maxlen[MAXN],dis[MAXN];
int nxt[MAXM],to[MAXM],w[MAXM];
int que[MAXN],id[MAXN],tot;

int Read(){
	int i=0,f=1;
	char c=getchar();
	for(;(c>'9'||c<'0')&&c!='-';c=getchar());
	if(c=='-')  f=-1,c=getchar();
	for(;c>='0'&&c<='9';c=getchar())  i=(i<<3)+(i<<1)+c-'0';
	return i*f;
}

void add(int x,int y){
	nxt[++cnt]=head[x];
	head[x]=cnt;
	to[cnt]=y;
}

void bfs1(int st){
	queue<int> q;
	q.push(st);
	viss[st]=1;
	while(!q.empty()){
		int u=q.front();
//		cout<<u<<' '<<dis[u]<<'\n';
		q.pop();
		for(int i=head[u];i!=-1;i=nxt[i]){
			int v=to[i];
			if(viss[v])  continue;
			dis[v]=dis[u]+1;
			q.push(v),viss[v]=1;
		}
	}
//	puts("");
}

void bfs2(int st){
	queue<int> q;
	q.push(st);
	while(!q.empty()){
		int u=q.front();
//		cout<<u<<' ';
		q.pop();
		vis[u]=1,que[++tot]=u;
		for(int i=head[u];i!=-1;i=nxt[i]){
			int v=to[i];
			if(dis[v]!=dis[u]-1||vis[v])  continue;
			q.push(v);
		}
	}
//	puts("");
}

int dfs3(int u,int f){
	int ret=0;
	for(int i=head[u];i!=-1;i=nxt[i]){
		int v=to[i];
		if(v==f||vis[v])  continue;
		ret=max(ret,dfs3(v,u)+1);
	}
	return ret;
}

void findmax(){for(int i=1;i<=tot;++i)  maxlen[que[i]]=dfs3(que[i],-1);}

bool check(int x){
	for(int i=x+1;i<=tot-x;++i){
//		if(x==1){
//			cout<<que[i]<<':';
//			cout<<maxlen[que[i]]<<' '<<dis[que[i]]<<'\n';
//		}
		if(maxlen[que[i]]+min(abs(dis[que[i]]-dis[que[x+1]]),abs(dis[que[i]]-dis[que[tot-x]]))>x)  return 0;
	}
	return 1;
}

void find(){
	int l=1,r=maxx,mid,ans;
	while(l<=r){
		mid=l+r>>1;
		if(check(mid))  ans=mid,r=mid-1;
		else  l=mid+1;
	}
	cout<<ans;
}

int main(){
	memset(head,-1,sizeof(head));
	n=Read();
	for(int i=1;i<n;++i){
		int x=Read(),y=Read();
		add(x,y),add(y,x);
	}
	bfs1(1);
	for(int i=1;i<=n;++i)  if(dis[i]>maxx)  maxx=dis[i],s=i;
	memset(dis,0,sizeof(dis));
	memset(viss,0,sizeof(viss));
	bfs1(s);
	maxx=0;
	for(int i=1;i<=n;++i)  if(dis[i]>maxx)  maxx=dis[i],t=i;
//	cout<<maxx<<'\n';
	bfs2(t);
	findmax();
//	for(int i=1;i<=tot;++i)  cout<<que[i]<<' '<<maxlen[i]<<'\n';
	find();
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值