蓝桥杯2023C++A组

(此文为简单的赛后记录,代码没有经过修改不保证正确

A 幸运数

将数字分为前一半和后一半dp方案数再乘起来

B 有奖问答

dpi,j表示第i轮 得分为10j的情况
注意一下在任意轮都可以结束并且j=10是不能转移的

C 平方差

当且仅当 \(x = 4^a * (2b+1) (a,b>=0)\) 统计

时间复杂度:\(O(log R)\)

D 更小的数

一个重要的观察:子串反转要么在首位和末尾比出大小,要么首位和末尾相等

做法一:\(dp_{i,j}\) 表示反转 j 到 j + i - 1 的子串是否更小 \(O(n^2)\)

做法而:分治,将左(右)区间每个位置看成一个二维的点(x,y),x是当前位置是什么数字,y是当前位置之前(之后)是什么数字,枚举右区间,对左区间统计二维前缀和就可以统计跨越左右区间贡献的答案

时间复杂度:\(O(n D^2 log n)\) D 是字符集大小,\(|D|=10\)

E 颜色平衡树

不会wuwu

F 买瓜

天天看华强结果一点思路都没有,,,

G 网络稳定性

说法很多

求最大生成树

之后就是一个求最小边的问题

考场写了倍增

\(O(N log \ M + (Q+N) log \ N)\)

#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
#define inf 1e7

using namespace std;

const int N = 200010, M = 300010;

int n,m,q,f[N][19],g[N][19],dep[N],fa[N],o,hd[N],vis[N];

struct edge{int u,v,w;}e[M];
struct Edge{int v,nt,w;}E[N<<1];

bool cmp(const edge&A,const edge&B){return A.w>B.w;}

void adde(int u,int v,int w){
	E[o]=(Edge){v,hd[u],w};hd[u]=o++;
	E[o]=(Edge){u,hd[v],w};hd[v]=o++;
}

int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}

void dfs(int u,int F){
	vis[u]=1;
	for(int i=1;(1<<i)<=dep[u];++i){
		f[u][i] = f[f[u][i-1]][i-1];
		g[u][i] = min(g[f[u][i-1]][i-1] , g[u][i-1]); //!
	}
	for(int i=hd[u];~i;i=E[i].nt){
		int v=E[i].v, w=E[i].w;
		if(v==F)continue;
		dep[v] = dep[u] + 1;
		f[v][0] = u;
		g[v][0] = w;
		dfs(v,u);
	}
}

int solve(int u,int v){
	int re=inf;
	if(dep[u]<dep[v])swap(u,v);
	int du=dep[u]-dep[v];
	for(int i=18;~i;--i)if((du>>i)&1)re=min(re,g[u][i]),u=f[u][i];
	if(u==v)return re;
	for(int i=18;~i;--i){
		if(f[u][i]!=f[v][i]){
			re = min(re, g[u][i]);
			re = min(re, g[v][i]);
			u = f[u][i], v=f[v][i];
		}
	}
	re = min(re, g[u][0]);
	re = min(re, g[v][0]);
	return re;
}

int main(){
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=m;++i){
		scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
	}
	//生成树 
	sort(e+1,e+m+1,cmp);
	for(int i=1;i<=n;++i)fa[i]=i,hd[i]=-1;
	for(int i=1;i<=m;++i){
		int fx = find(e[i].u);
		int fy = find(e[i].v);
		if(fx == fy)continue;
		fa[fy]=fx;
		adde(e[i].u,e[i].v,e[i].w);
	}
	//倍增求答案 
	for(int i=1;i<=n;++i)if(!vis[i])dfs(i,0);
	for(int i=1;i<=q;++i){
		int u,v;
		scanf("%d%d",&u,&v);
		if(find(u)!=find(v)){puts("-1");continue;}
		cout<<solve(u,v)<<endl;
	}
	return 0;
}

H 异或和之和

按位统计答案,统计异为0 和 1的前缀个数相乘即可

I 像素放置

我想写插头dp
没有写出来,最后二十分钟来调暴力也没调出来,很可惜50%
吸取教训:像这种题肯定是先写暴力的,就算要写正解也需要暴力来对拍

\(O(NM4^M)\) 不知道能不能过。。。等题解

J 翻转硬币

不会做orz

posted @ 2023-04-09 10:40  tkys_AUSTIN  阅读(169)  评论(0编辑  收藏  举报