蓝桥杯2021初赛B 题解 | JorbanS

[蓝桥杯2021初赛] 卡片

Tag 枚举

题意09 的卡片,每种有 2021 张,一张卡片仅能用一次,从 1 开始拼,输出最大拼出的数

#include
using namespace std;
int a[10];

int solve(){
	for(int i=1;;i++){		
		int x=i;
		while(x){
			int t=x%10;
			if(a[t]==0)return i-1;
			a[t]--;
			x/=10;
		}
	}
}

int main(void){
	for(int i=0;i<10;i++)a[i]=2021;
	cout<<solve()<<endl;
	return 0;
}

[蓝桥杯2021初赛] 直线

Tag 枚举 数学

题意 给定平面上 20 × 21 个整点 {(x, y)|0 ≤ x < 20, 0 ≤ y < 21, x ∈ Z, y ∈ Z},连接并贯穿两个点形成直线,输出一共能形成的直线数量

分析 需要特殊处理与坐标轴平行的直线

#include
#include
using namespace std;
set<pair<double,double>> s;
set<int> px,py;

void solve(double x1,double x2,double y1,double y2){
	if(y1==y2){
		py.insert(y1);
		return;
	}
	if(x1==x2){
		px.insert(x1);
		return;
	}
	double k,b;
	k=(y1-y2)/(x1-x2);
	b=(x1*y2-x2*y1)/(x2-x1);
	s.insert({k,b});
}

int main(void){
	for(double x1=0;x1<20;x1++)
		for(double y1=0;y1<21;y1++)
			for(double x2=0;x2<20;x2++)
				for(double y2=0;y2<21;y2++)
					solve(x1,x2,y1,y2);
	cout<<s.size()+px.size()+py.size()<<endl;
	return 0;
}

[ 蓝桥杯2021初赛] 货物摆放

Tag 枚举

题意 堆长方体,体积为 2021041820210418,有多少种整数解

#include
using namespace std;
typedef long long ll;
ll res,n=2021041820210418;
ll a[150],idx;

int main(void){
	for(int i=1;i<=n/i;i++){
		if(n%i==0){
			a[idx++]=i,a[idx++]=n/i;
			if(i==n/i)idx--;
		}
	}
	for(int i=0;i<idx;i++)
		for(int j=0;j<idx;j++)
			for(int k=0;k<idx;k++)
				if(a[i]*a[j]*a[k]==n)res++;
	cout<<res<<endl;
	return 0;
}

[蓝桥杯2021初赛] 路径

Tag Dijkstra最短路 gcd/lcm

题意2021 个结点组成的图,编号 1~2021,若 a-b 的差小于等于 21ab 相连的无向边长度为两者的最小公倍数,反之不存在相连的边,结点 1 和结点 2021 之间的最短路径长

#include
#include
#include
using namespace std;
typedef pair<int,int> PII;
const int N=2022,M=2*N*43;
int idx,h[N],e[M],ne[M],w[M];
int d[N];
bool st[N];

int gcd(int a,int b){return b?gcd(b,a%b):a;}
int lcm(int a,int b){return a*b/gcd(a,b);}
void add(int a,int b,int c){
	e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

int Dijkstra(){
	priority_queue<PII,vector<PII>,greater<PII>> heap;
	heap.push({0,1});
	d[1]=0;
	while(heap.size()){
		auto t=heap.top();
		heap.pop();
		int ver=t.second,dis=t.first;
		if(st[ver])continue;
		st[ver]=1;
		for(int i=h[ver];i!=-1;i=ne[i]){
			int j=e[i];
			if(d[j]>d[ver]+w[i]){
				d[j]=d[ver]+w[i];
				heap.push({d[j],j});
			}
		} 
	}
	return d[2021];
}

int main(){
	memset(h,-1,sizeof h);
	memset(d,0x3f,sizeof d);
	for(int i=1;i<N;i++)
		for(int j=1;j<N;j++)
			if(abs(i-j)<=21){
				int t=lcm(i,j);
				add(i,j,t),add(j,i,t);
			}
	cout<<Dijkstra()<<endl;
	return 0;
}

[蓝桥杯2021初赛] 空间

Tag 进制

题意 256MB 内存空间能存放多少个 32 位二进制整数,不考虑程序占用的空间和维护内存需要的辅助空间

#include
using namespace std;

int main(){
	cout<<1ll*256*1024*1024*8/32<<endl;
	return 0;
}

[蓝桥杯2021初赛] 砝码称重

Tag dp

题意 一架天平,n 个砝码,质量分别为 w[i],砝码可以放在天平两端,求一共能称出多少种不同的质量

#include
using namespace std;
const int N=101,M=1e5+1;
int n,s,res;
int a[N];
bool dp[N][M]; // dp[i][j] 前 i 个砝码能称出 j

int main(void){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i],s+=a[i];
	dp[0][0]=1;
	for(int i=1;i<=n;i++)
		for(int j=0;j<=s;j++)
			if(dp[i-1][j]||dp[i-1][j+a[i]]||dp[i-1][abs(j-a[i])])
				dp[i][j]=1;
	for(int i=1;i<=s;i++)
		if(dp[n][i])res++;
	cout<<res<<endl;
	return 0;
}

[蓝桥杯2021初赛] 括号序列

题意 给定一个含 () 的字符串,求使得插入括号最少的且使得括号字符串合法的有多少种

[ 蓝桥杯2021初赛] 时间显示

Tag 数学

题意 输入为 1970 年 1 月 1 日 00:00:00 开始经过的毫秒数,输出为 HH:MM:SS 格式的时间

#include
using namespace std;
typedef long long ll;
const int m=60,h=m*60,d=h*24;

int main(void){
	int T;cin>>T;
	while(T--){
		ll x;cin>>x;
		x/=1000;
		int hh,mm;
		x%=d;
		hh=x/h,x%=h;
		mm=x/m,x%=m;
		printf("%02d:%02d:%02d\n",hh,mm,x);
	}
	return 0;
}

[ 蓝桥杯2021初赛] 杨辉三角形

Tag 组合数

题意 给出 tn 满足 1 ≤ n ≤ 1e9,分别求杨辉三角形中第一次出现 n 的序号

分析 杨辉三角形左右对称,斜着第一个数是 C(i, 2i)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DVYNOZQV-1679052944937)(null)]

            1  ---> C(0, 0)
          1 
        1   2  ---> C(1, 2)
      1   3
    1   4   6  ---> C(2, 4)
  1   5   10
1   6   15  20 ---> C(3, 6)
#include
using namespace std;
typedef long long ll;
int x;

ll C(int a,int b){
   ll res=1;
   for(int i=b,j=1;j<=a;i--,j++){
   	res=res*i/j;
   	if(res>x)return res;
   }
   return res;
}

int main(void){
   int T;cin>>T;
   while(T--){
   	cin>>x;
   	for(int i=16;;i--){ // C(16,32) < 1e9 < C(17,34)
   		int l=2*i,r=max(x,l);
   		while(l<r){
   			int mid=l+r>>1;
   			if(C(i,mid)>=x)r=mid;
   			else l=mid+1;
   		}
   		if(C(i,r)==x){
   			cout<<1ll*(r+1)*r/2+i+1<<endl;
   			break;
   		}
   	}
   }
   return 0;
}

[蓝桥杯2021初赛] 双向排序

题意 n 个数 a[i] = i,进行 m 次操作,每次输入 p[i] q[i]

  • p[i] = 0a[1] .. a[q[i]] 降序排列

  • p[i] = 1a[q[i]] .. a[n] 升序排列

分析 此题使用 sortTLE,仅能够 AC 60%

你可能感兴趣的:(OI,题解,算法,蓝桥杯,c++)