10.7 解题报告

T1

考场用时:\(40\) min
期望得分:\(100\) pts
实际得分:\(100\) pts
我们都知道,这题是一个并查集的板子题,于是考虑BFS
一开始把擦着底边的推进队列。
然后,对于所有的空洞,枚举一遍其他空洞,把能连起来的推进队列。
最后如果有顶到顶的就是 Yes,不然就是 No。

#include<bits/stdc++.h>
#define ll long long
#define int long long
#define lc(k) k<<1
#define rc(k) k<<1|1
using namespace std;
const int MAX=1e3+10;
const int MOD=1e9+7;
inline char readchar() {
	static char buf[100000], *p1 = buf, *p2 = buf;
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
inline int read() {
// #define readchar getchar
	int res = 0, f = 0;
	char ch = readchar();
	for(; !isdigit(ch); ch = readchar()) if(ch == '-') f = 1;
	for(; isdigit(ch);ch = readchar()) res = (res << 1) + (res << 3) + (ch ^ '0');
	return f ? -res : res;
}
inline void write(int x) {
    if(x<0){putchar('-');x=-x;}
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
int x[MAX],y[MAX],z[MAX],vis[MAX];
queue<int> q;
int dis(int a,int b){
	int dx=x[a]-x[b],dy=y[a]-y[b],dz=z[a]-z[b];
	return dx*dx+dy*dy+dz*dz;
}
signed main(){
	int T=read();
	while(T--){
		int n=read(),h=read(),r=read(),f=0;
		memset(vis,0,sizeof vis);
		while(!q.empty()) q.pop();
		for(int i=1;i<=n;i++){
			x[i]=read(),y[i]=read(),z[i]=read(); 
			if(z[i]<=r&&z[i]>=-r) q.push(i);
		}
		while(!q.empty()){
			int ff=q.front();q.pop();
			if(vis[ff]) continue;
			if(z[ff]>=h-r&&z[ff]<=h+r) {f=1;puts("Yes");break;}
			vis[ff]=1;q.push(ff);
			for(int i=1;i<=n;i++){
				if(i==ff) continue;
				if(dis(i,ff)<=4*r*r) q.push(i);
			}
		}
		if(!f) puts("No");
	}
	return 0;
}

T2

考场用时:\(40\) min
期望得分:\(70\) pts
实际得分:\(75\) pts
考场写了枚举顺序的 \(O(n!)\) 暴力,加了几个剪枝,多得了 \(5\) pts。
正解是考虑状压 dp,设 \(dp_{i,s}\) 表示挖掘了 \(i\) 层,此时联通的集合是 \(s\) 的最小花费,转移即:\(dp_{i,s}=\min\{dp_{t,i-1}+i\times w(t,s)\}\),其中 \(w\) 可以 \(O(3^n n^2)\) 预处理,dp \(O(3^n n^2)\),总的复杂度即为 \(O(3^nn^2)\),需要用到枚举子集的小技巧:

for(int T=S;T;T=S&(T-1))

当然这题充分利用性质,多加几个剪枝,也是可以过的。

#include<bits/stdc++.h>
#define ll long long
//#define int long long
#define lc(k) k<<1
#define rc(k) k<<1|1
using namespace std;
const int MAX=3e5+10;
const int MOD=1e9+7;
inline char readchar() {
	static char buf[100000], *p1 = buf, *p2 = buf;
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
inline int read() {
#define readchar getchar
	int res = 0, f = 0;
	char ch = readchar();
	for(; !isdigit(ch); ch = readchar()) if(ch == '-') f = 1;
	for(; isdigit(ch);ch = readchar()) res = (res << 1) + (res << 3) + (ch ^ '0');
	return f ? -res : res;
}
inline void write(int x) {
    if(x<0){putchar('-');x=-x;}
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
int n,m,dis[20][20],ans=MOD,f[20],js,lim;
void dfs(int sum,int noww){
    ++js;if(js>lim) return ;
	if(sum==n) return ans=min(ans,noww),void();
	if(noww>=ans) return ;
	for(register int i=1;i<=n;i++){
		if(f[i]==1e9) continue;
		for(register int j=1;j<=n;j++){
			if(dis[i][j]==1e9||f[j]<1e9||i==j) continue;
			f[j]=f[i]+1;
//			cout<<i<<" "<<j<<endl;
			dfs(sum+1,noww+f[i]*dis[i][j]);
			f[j]=1e9;
		}
	}
	return ;
}
signed main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++) dis[i][j]=1e9;
		dis[i][i]=0; 
	}
	for(int i=1;i<=m;i++){
		int u=read(),v=read(),w=read();
		dis[u][v]=dis[v][u]=min(dis[u][v],w);
	}
	lim=6.6e7/n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++) f[j]=1e9;
		f[i]=1;js=0;dfs(1,0);
	}
	cout<<ans;
	return 0;
} 

T3

考场用时:\(30\) min
期望得分:\(30\) pts
实际得分:\(30\) pts
直接队列模拟,就可以得到 \(30\) 分。

#include<bits/stdc++.h>
#define ll long long
//#define int long long
#define lc(k) k<<1
#define rc(k) k<<1|1
using namespace std;
const int MAX=3e5+10;
const int MOD=1e9+7;
inline char readchar() {
	static char buf[100000], *p1 = buf, *p2 = buf;
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
inline int read() {
#define readchar getchar
	int res = 0, f = 0;
	char ch = readchar();
	for(; !isdigit(ch); ch = readchar()) if(ch == '-') f = 1;
	for(; isdigit(ch);ch = readchar()) res = (res << 1) + (res << 3) + (ch ^ '0');
	return f ? -res : res;
}
inline void write(int x) {
    if(x<0){putchar('-');x=-x;}
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
int n,m,q,ans[1001][1001];
void subtask1(){
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			ans[i][j]=(i-1)*m+j;
	while(q--){
		int x=read(),y=read(),t=ans[x][y];
		cout<<t<<'\n';
		for(int i=y+1;i<=m;i++) ans[x][i-1]=ans[x][i];
		for(int i=x+1;i<=n;i++) ans[i-1][m]=ans[i][m];
		ans[n][m]=t;
	}
	return ;
}
signed main(){
	n=read(),m=read(),q=read();
	if(n<=50000&&m<=50000) subtask1();
//	if(n==1&&m<=1e5) subtask3();
}
posted @ 2022-11-07 22:50  wapmhac  阅读(15)  评论(0编辑  收藏  举报