第十四届蓝桥杯大赛题解

A题(填空)日期统计

dfs+剪枝

第十四届蓝桥杯大赛题解_第1张图片

#include 
#define ll long long
#define INF 0x7f7f7f7f
using namespace std;

const int N=3e8+10;

int n,m,ans,k;
int a[110],vis[N];

bool check(int date) {
	if(vis[date])return false;
	vis[date]=1;
	int mm=date/100%100;
	int dd=date%100;
	if(mm<1||mm>12)return false;
	if(mm==1||mm==3||mm==5||mm==7||mm==8||mm==10||mm==12) {
		if(dd>=1&&dd<=31)return true;
	} else if(mm==2) {
		if(dd>=1&&dd<=28)return true;
	} else if(dd>=1&&dd<=30)return true;

	return false;
}


void dfs(int x,int cnt,int date) { //传入当前位置,第几位,日期

	if(x==100)return ;
	if(cnt==8) {
		if(check(date))ans++;
		return ;
	}

	if((cnt==0&&a[x]==2)||(cnt==1&&a[x]==0)||(cnt==2&&a[x]==2)||(cnt==3&&a[x]==3)||(cnt==4&&a[x]>=0&&a[x]<=1)||(cnt==5&&a[x]>=0&&a[x]<=9)||(cnt==6&&a[x]>=0&&a[x]<=3)||(cnt==7&a[x]>=0&&a[x]<=9))
		dfs(x+1,cnt+1,date*10+a[x]);//合法可以选

	dfs(x+1,cnt,date);//不选

}




int main() {


	/*
	5 6 8 6 9 1 6 1 2 4 9 1 9 8 2 3 6 4 7 7 5 9 5 0 3 8 7 5 8 1 5 8 6 1 8 3 0 3 7 9 2
	7 0 5 8 8 5 7 0 9 9 1 9 4 4 6 8 6 3 3 8 5 1 6 3 4 6 7 0 7 8 2 7 6 8 9 5 6 5 6 1 4 0 1
	0 0 9 4 8 0 9 1 2 8 5 0 2 5 3 3
	*/

	for(int i=0; i<100; i++)cin>>a[i];
	dfs(0,0,0);
	cout<<ans;

	return 0;
}

答案:235

B题(填空)01串的熵

第十四届蓝桥杯大赛题解_第2张图片

考察枚举,遇见这种式子不要慌,慢慢分析推导

注意浮点数的处理方式每次用1.0乘上一个int数转为浮点数

注意log函数的使用

注意结果的判断方式

第十四届蓝桥杯大赛题解_第3张图片

#include 
#define ll long long
#define INF 0x7f7f7f7f
using namespace std;

const int N=23333333;

int n,m,k;

double ans=11625907.5798,esp=1e-4;



int main() {


     for(int m=0;m<=N/2;m++){//枚举0的个数 
     	 n=N-m;//1的个数
		 double res=-1.0*m*m/N*log2(1.0*m/N)-1.0*n*n/N*log2(1.0*n/N);
		 if(fabs(res-ans)<esp){
		 	cout<<m<<endl;
			 return 0; 
		 } 
	 }




	return 0;
}

C题冶炼金属

第十四届蓝桥杯大赛题解_第4张图片

二分转换率

#include 
#define ll long long
#define INF 0x7f7f7f7f
using namespace std;

const int N=1e4+10;

int n,m,k,ans;
int a[N],b[N];


bool  check_min(int v) {
	for(int i=1; i<=n; i++) {
		if(a[i]/v>b[i])return false;
	}
	return true;
}

bool check_max(int v) {
	for(int i=1; i<=n; i++) {
		if(a[i]/v<b[i])return false;
	}
	return true;
}


int main() {

	cin>>n;
	for(int i=1; i<=n; i++)cin>>a[i]>>b[i];

	int l=0,r=1e9;

	while(l<r) {
		int mid=l+r>>1;
		if(check_min(mid)) {
			r=mid;
		} else {
			l=mid+1;
		}
	}
	cout<<r<<" ";
	
	l=0,r=1e9;
	while(l<r){
		int mid=l+r+1>>1;
		if(check_max(mid))l=mid;
		else r=mid-1; 
	}
    cout<<r<<endl;


	return 0;
}

D题飞机降落

全排列

第十四届蓝桥杯大赛题解_第5张图片

#include 
#define ll long long
#define INF 0x7f7f7f7f
using namespace std;

const int N=20;

int n,m,k,ans;
bool flag;
int  T[N],D[N],L[N];
int vis[N]; 

void dfs(int k,int t) { //已经放了k架飞机,当前时间为t

	if(k==n) {
		flag=true;
		return ;
	}
	for(int i=1; i<=n; i++) {
		if(!vis[i]) {
			if(T[i]+D[i]>=t) {
				vis[i]=1;
				dfs(k+1,max(t+L[i],T[i]+L[i]));//注意这里要取最大,因为飞机可能没有到达 
				vis[i]=0;
			}
		}
	}

}



int main() {

	int t;
	cin>>t;
	while(t--) {
		memset(vis,0,sizeof(vis));
		flag=false;
		cin>>n;
		for(int i=1; i<=n; i++) {
		    cin>>T[i]>>D[i]>>L[i]; 
		}
		for(int i=1; i<=n; i++) {
			if(!vis[i]) {
				vis[i]=1;
				dfs(1,T[i]+L[i]);
				vis[i]=0;
			}
		}
		if(flag)cout<<"YES"<<endl;
		else cout<<"NO"<<endl; 
	}
	return 0;
}

E题接龙数字

第十四届蓝桥杯大赛题解_第6张图片

dp

#include 

#define ll long long

using namespace std;

typedef pair<int,int> PII;
const int N=1e5+10;

int n,m,ans;

int f[N][10];
int a[N];

int fun(int x) {
	while(x/10) x/=10;
	return x;
}

int main() {

	/*
	5
	11 121 22 12 2023
	*/

	cin>>n;

	for(int i=1; i<=n; i++)cin>>a[i];


	for(int i=1; i<=n; i++) {
		for(int j=0; j<=9; j++) {
			f[i][j]=f[i-1][j];//先继承 
		}
		f[i][a[i]%10]=max(f[i][a[i]%10],f[i-1][fun(a[i])]+1);//要么是继承的结果大,要么是把他加入新的序列结果大 
	}

	ans=-1;
	for(int i=0; i<=9; i++) {
		ans=max(f[n][i],ans);
	}
	cout<<n-ans;



	return 0;

}

F题岛屿个数

第十四届蓝桥杯大赛题解_第7张图片

bfs染色问题
首先遍历每一个点从每一个点出发如果该点为陆地那么进行染色,把上下左右相邻的陆地全部染色
在进行判断,从该点出入,一直在海里游向八个方向游泳,如果能够游到边界,那么该点和该点染色的陆地形成独立的岛屿,如果游不出去,那么该点和延申的岛屿均为子岛

注意游泳的时候一定为八个方向下图就为3个岛屿,中间两个均可以游出去
第十四届蓝桥杯大赛题解_第8张图片

#include 
#define ll long long
#define INF 0x7f7f7f7f
using namespace std;

const int N=60;

int n,m,k,ans;
int dx[8]= {1,0,-1,0,1,-1,-1,1}; //上右下左,右上、右下、左下、左上
int dy[8]= {0,1,0,-1,1,1,-1,-1};
int vis[N][N];
int used[N][N];
string M[N];//必须用string int读入必须有空格

void bfs_col(int x,int y) {
	queue<int>qx,qy;
	qx.push(x);
	qy.push(y);
	while(!qx.empty()) {
		x=qx.front(),y=qy.front();
		qx.pop(),qy.pop();
		//上右下左四个方向bfs
		for(int i=0; i<4; i++) {
			int nx=x+dx[i];
			int ny=y+dy[i];
			if(nx<0 || nx>=n || ny<0 || ny>=m || vis[nx][ny] || M[nx][ny]=='0') continue;//不合法
			qx.push(nx);
			qy.push(ny);
			vis[nx][ny]=1;
		}
	}
}

bool bfs_out(int x,int y) {
	memset(used,0,sizeof(used));
	queue<int>qx,qy;
	qx.push(x);
	qy.push(y);
	used[x][y]=1;
	while(!qx.empty()) {
		x=qx.front();
		qx.pop();
		y=qy.front();
		qy.pop();
		if(x==0 || x==n-1 || y==0 || y==m-1) return true;;//走到边界证明该岛屿为单个岛
		for(int i=0; i<8; i++) {
			int nx=x+dx[i];
			int ny=y+dy[i];
			if(nx<0 || nx>=n || ny<0 || ny>=m || used[nx][ny] || M[nx][ny]=='1') continue;
			qx.push(nx);
			qy.push(ny);
			used[nx][ny]=1;
		}
	}
	return false;
}



int main() {

	int T;
	cin>>T;
	while(T--) {
		memset(vis,0,sizeof(vis));
		cin>>n>>m;//n行m列
		for(int i=0; i<n; i++)
			cin>>M[i];

		ans=0;
		for(int i=0; i<n; i++) {
			for(int j=0; j<m; j++) {
				if(!vis[i][j]&&M[i][j]=='1') {
					vis[i][j]=1;
					bfs_col(i,j);//把所有上下左右相邻的1染色
					if(bfs_out(i,j))ans++;
				}
			}
		}
		cout<<ans<<endl;
	}






	return 0;

}

G题目子串简写

双指针+前缀和
以当前点位右端点,向左想(不要总是从左向右想)

#include 
#define ll long long
#define INF 0x7f7f7f7f
using namespace std;

const int N=60;

ll n,m,k,ans;



int main() {

	cin>>k;
	string str;
	cin>>str;
	char c1,c2;
	cin>>c1>>c2;
    n=str.size(); 
	ll sum=0;
	//i和j保持k的距离 
	for(int i=k-1,j=0; i<n; i++,j++) { //双指针+前缀和
		if(str[j]==c1) sum++;
		if(str[i]==c2) ans+=sum;//碰到一个c2就开始收割 
	}
    
    cout<<ans<<endl; 


	return 0;
}

H题整数删除

优先队列+链表

#include 
#define ll long long
#define INF 0x7f7f7f7f

using namespace std;
typedef pair<ll,int> PII;

const int N=5e5+10;

int  n,m,k,ans;
ll pre[N],nex[N];v[N];
priority_queue<PII,vector<PII>,greater<PII> > q;

void del(int x) {
	nex[pre[x]]=nex[x];
	pre[nex[x]]=pre[x];
	v[pre[x]]+=v[x],v[nex[x]]+=v[x];
}


int main() {

	cin>>n>>k;
	pre[n+1]=n,nex[0]=1;//初始化双向链表 
	//创建链表
	for(int i=1; i<=n; i++) {
		cin>>v[i];
		pre[i]=i-1;
		nex[i]=i+1;
		q.push({v[i],i});
	}
	while(k--) {
		PII p=q.top();
		q.pop();
		if(p.first!=v[p.second])q.push({v[p.second],p.second}),k++;//更新重新放入堆
		else del(p.second);
	}
	int p=nex[0];
	while(p!=n+1) {
		cout<<v[p]<<" ";
		p=nex[p];
	}

	return 0;
}

I景区导游

第十四届蓝桥杯大赛题解_第9张图片

LCA应用求树上两点间距离

#include 
#define ll long long
#define INF 0x7f7f7f7f

using namespace std;
typedef pair<ll,int> PII;

const int N=1e5+10;

int  n,m,ecnt;
int f[N][30];
int d[N],head[N];
int A[N];
ll sum[N];
struct edge {
	int u,v,w,next;
} E[N<<1];

void add(int u,int v,int w) {
	E[++ecnt].u=u;
	E[ecnt].v=v;
	E[ecnt].w=w;
	E[ecnt].next=head[u];
	head[u]=ecnt;
}

void dfs(int u,int fa) {
	d[u]=d[fa]+1;
	f[u][0]=fa;
	for(int i=1; i<=20; i++)
		f[u][i]=f[f[u][i-1]][i-1];
	for(int i=head[u]; i; i=E[i].next) {
		int v=E[i].v;
		if(fa!=v) {
			sum[v]=sum[u]+E[i].w;
			dfs(v,u);
		}
	}
}

int LCA(int x,int y) {
	if(d[x]<d[y])swap(x,y);

	for(int i=20; i>=0; i--) {
		if(d[f[x][i]]>=d[y])x=f[x][i];
	}

	if(x==y)return x;

	for(int i=20; i>=0; i--) {
		if(f[x][i]!=f[y][i]) {
			x=f[x][i];
			y=f[y][i];
		}
	}
	return f[x][0];
}

ll path_dis(int x,int y) {
	if(x==0||y==0)return 0;
	return sum[x]+sum[y]-2*sum[LCA(x,y)];
}

int main() {

	cin>>n>>m;
	for(int i=1; i<n; i++) {
		int u,v,w;
		cin>>u>>v>>w;
		add(u,v,w);
		add(v,u,w);
	}
	dfs(1,0);

	ll ans=0;
	for(int i=1; i<=m; i++) {
		cin>>A[i];
		ans+=path_dis(A[i],A[i-1]);
	}
	//减去前一段,前去后一段,加上新的一段
	for(int i=1; i<=m; i++) {
		cout<<ans-path_dis(A[i],A[i-1])-path_dis(A[i],A[i+1])+path_dis(A[i-1],A[i+1])<<" ";
	}


	return 0;
}

J题砍树

第十四届蓝桥杯大赛题解_第10张图片

树上差分

#include 
#define ll long long
#define INF 0x7f7f7f7f

using namespace std;
typedef pair<ll,int> PII;

const int N=1e5+10;

int  n,m,ecnt,ans;
int f[N][30];
int d[N],head[N];
int cnt[N];
struct edge{
	int u,v,next;
} E[N<<1];

void add(int u,int v) {
	E[++ecnt].u=u;
	E[ecnt].v=v;
	E[ecnt].next=head[u];
	head[u]=ecnt;
}

void  dfs(int u,int fa) {
	d[u]=d[fa]+1;
	f[u][0]=fa;
	for(int i=1; i<=20; i++)
		f[u][i]=f[f[u][i-1]][i-1];

	for(int i=head[u]; i; i=E[i].next) {
		int v=E[i].v;
		if(v==fa)continue;
		dfs(v,u);
	}
}

int lca(int x,int y) {
	if(d[x]<d[y])swap(x,y);
	for(int i=20; i>=0; i--) {
		if(d[f[x][i]]>=d[y])x=f[x][i];
	}
	if(x==y)return x;
	for(int i=20; i>=0; i--) {
		if(f[x][i]!=f[y][i]) {
			x=f[x][i];
			y=f[y][i];
		}
	}
	return f[x][0];
}

void dfs2(int u,int fa) {
	for(int i=head[u]; i; i=E[i].next) {
		int v=E[i].v;
		if(v==fa)continue;
		dfs2(v,u);
		cnt[u]+=cnt[v];//树上差分 
		if(cnt[v]==m)ans=max(ans,i);//所有不同点,的公共路径 
	}
}

int main() {

	cin>>n>>m;
	for(int i=1; i<n; i++) {
		int u,v;
		cin>>u>>v;
		add(u,v);
		add(v,u);
	}
	dfs(1,0);
	for(int i=1; i<=m; i++) {
		int a,b;
		cin>>a>>b;
		cnt[a]++,cnt[b]++,cnt[lca(a,b)]-=2;
	}
	dfs2(1,0);
	cout<<(ans+1)/2<<endl;//每次建立双向边所以要除以2 


	return 0;
}

你可能感兴趣的:(其他基础技巧,图论,深度优先,算法,c++,蓝桥杯)