[HBCPC2024] 2024 年湖北省大学生程序设计竞赛重现赛题解

比赛链接:HBCPC2024

还是和 @cyx20110930 组的队,只不过用我的号交的。(rk. 26)这次我也橙了 开心.jpg

由于 @cyx20110930 在车上,电脑又快没电了,所以他只上线 1h。但居然写了 2 题,还口胡出了2 题,%%%

其实H题也很简单,一个 dfs。但由于我水平太菜,时间不够,没来及写。大家可以去尝试一下。

Problem A:

安利一波 @cyx20110930 的题解

题目意思

输入x,y,输出乘积最大的两个数a,b 使得a \sqrt{b}=\sqrt{\frac{lcm(x,y)}{gcd(x,y)}}​​。

思路

数学题,秒了。直接先算出\sqrt{\frac{lcm(x,y)}{gcd(x,y)}}的值。然后为了让a\times b最大,直接输出1\frac{lcm(x,y)}{gcd(x,y)}即可。

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
	int T;
	cin>>T;
	while(T--){
		int x,y;
		cin>>x>>y;
		int gcd=__gcd(x,y);
		int lcm=x*y/gcd;
		cout<<lcm/gcd<<' '<<1<<endl;
	}
	return 0;
}

Problem B:

这题是 CYX 写的。所以copy一下他的题解。(bushi

题目意思

平面上有一些点,问你用其中至少三个点组成的图形的面积最小是多少,如果组不了,输出  -1。

思路

很明显最小的一定是三角形。

证明:任何一个正 n 边形,都可以分成一个三角形,与一个正 n-1 边形,自然三角形的面积小于这个正 n 边形。

所以直接暴力枚举三角形用海伦公式求面积即可。

代码

孩子不判三点共线,多半是废了!

#include <bits/stdc++.h>
using namespace std;
struct node{
    double x,y;
}po[1000005];
void solve(){
    double ans=0x3f;
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>po[i].x>>po[i].y;
    }
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            for(int z=j+1;z<=n;z++){
                double sum=po[j].x*po[z].y-po[z].x*po[j].y+po[i].x*po[j].y-po[j].x*po[i].y-po[i].x*po[z].y+po[z].x*po[i].y;
                sum=abs(sum);
                if (sum != 0){
                    ans=min(ans,sum/2.0);
                }
            }
        }
    }
    if (ans==0x3f){
        cout<<-1<<endl;
    }
    else{
        cout<<ans<<endl;
    }
}
int main(){
    int t;
    while(t--){
        solve();
    }
}

Problem E:

签到。

题目意思

一共 n 人,每人可以选 b 美刀的 Grilled Chicken Burger Set 或 a 美刀的 Spicy Chicken Burger Set。其中选 Grilled Chicken Burger Set 有 x 人,问总共花了几美刀?

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
int main(){
	int T;
	cin>>T;
	while(T--){
		int n,x,a,b;
		cin>>n>>x>>a>>b;
		cout<<(n-x)*a+x*b<<endl;
	}
	return 0;
}

Problem G:

原神,启动!(我不玩原神)

题目意思

在一局围棋中,给你黑方与白方每一步的落子,问你每一步黑白双方有几个子被吃?

思路

很简单,我们可以每一步落子之后,对这个棋子周围的五个位置的联通块处理即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int dx[4]={0,0,1,-1};
const int dy[4]={1,-1,0,0};
int board[30][30],ans[10],n=19;
bool used[30][30];
void bfs(int x,int y){
	int col=board[x][y];
	queue<pair<int,int>> que;
	vector<pair<int,int>> v;
	que.push(make_pair(x,y));
	used[x][y]=true;
	bool ok=false;
	while(!que.empty()){
		auto [x,y]=que.front();
		que.pop();
		v.push_back(make_pair(x,y));
		for(int i=0;i<4;i++){
			int nx=x+dx[i],ny=y+dy[i];
			if(nx<1 || nx>n || ny<1 || ny>n)
				continue;
			if(board[nx][ny]==-1)
				ok=true;
			if(board[nx][ny]!=col || used[nx][ny])
				continue;
			que.push(make_pair(nx,ny));
			used[nx][ny]=true;
		}
	}
	if(!ok){
		for(auto &[x,y]:v){
			board[x][y]=-1;
			ans[col]++;
		}
	}
	return;
}
void solve(int col,vector<pair<int,int>> &v){
	memset(used,0,sizeof(used));
	for(auto &[x,y]:v){
		if(x<1 || x>n || y<1 || y>n)
			continue;
		if(used[x][y])
			continue;
		if(board[x][y]!=col)
			continue;
		bfs(x,y);
	}
	for(auto &[x,y]:v){
		if(x<1 || x>n || y<1 || y>n)
			continue;
		if(used[x][y])
			continue;
		if(board[x][y]!=1^col)
			continue;
		bfs(x,y);
	}
	return;
}
int main(){
	memset(board,-1,sizeof(board));
	int m;
	cin>>m;
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y;
		int col=i%2;
		board[x][y]=col;
		ans[1]=ans[0]=0;
		vector<pair<int,int>> v;
		for(int i=0;i<4;i++)
			v.push_back(make_pair(x+dx[i],y+dy[i]));
		v.push_back(make_pair(x,y));
		solve(col^1,v);
		cout<<ans[0]<<' '<<ans[1]<<endl;
	}
	return 0;
}

Problem J:

是 @cyx20110930 写的,所以跟我无关(bushi

他的题解:here

题目意思

有一个序列a_1,a_2,......a_n​,问对于所有 1 到 n 的排列p_1,p_2,...p_n,算出的\frac{\frac{\frac{a_{p_1}+a_{p_2}}{2}+a_{p_3}}{2}+a_{p_4}}{2}... 的期望对 998244353 的取模。

思路

结论:平均数。

证明

记答案为Sum(a,n)

若 a 数组有 n 项,期望为

Sum(a,n)=\frac{1}{\frac{n\times (n-1)}{2}}\times (Sum(\begin{Bmatrix} \frac{a_1+a_2}{2},a_3,...\end{Bmatrix},n-1)+Sum(\begin{Bmatrix} \frac{a_1+a_3}{2},a_2,...\end{Bmatrix},n-1)+...+Sum(\begin{Bmatrix} \frac{a_{n-1}+a_n}{2},a_1,...\end{Bmatrix},n-1))=\frac{1}{\frac{n\times (n-1)^2}{2}}\times ((n-1\times \frac{1}{2}+(n-1))\times 1)\times (a_1+a_2+...+a_n))=\frac{1}{\frac{n\times (n-1)^2}{2}}\times (\frac{(n-1)^2}{2})\times (a_1+a_2+...+a_n)=\frac{1}{n}\times (a_1+a_2+...a_n)

证毕!还是平均数。

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define mod 998244353
int qmi(int a,int b,int p){
	int res=1;
	while(b){
		if(b&1) res=res*a%p;
		b>>=1;
		a=a*a%p;
	}
	return res;
}
int main(){
    int n;
    cin>>n;
    int x,ans=0;
    for(int i=1;i<=n;i++){
    	cin>>x;
    	ans+=x;
    }
    ans=ans%mod;
	ans=ans*qmi(n,mod-2,mod)%mod;
	cout<<ans;
}

Problem L:

题目意思

给定起点和终点,求起点到终点的最短路径,任意两点的路径为lcm(u,v)

思路

首先特判x=y,输出0。

假设x<y

  • y=kx时,代价是 y。
  • 当 x 和 y 不互质是,可以 x→gcd(x,y)→y,代价为 x+y
  • 当 x 和 y 互质时:中间经过的点必然都是质数。让经过的质数越小越好。

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
int lcm(int a,int b){
	return a*b/__gcd(a,b);
}
void solve(){
    int a,b;
	cin>>a>>b;
    if(a==b){
    	cout<<0<<endl;
    	return;
    }
    vector<int> A,B;
    A.push_back(2);
	B.push_back(2);
    A.push_back(a);
	B.push_back(b);
    for(int i=2;i<=a/i;i++){
    	if(a%i==0){
    		int x=i,y=a/i;
    		if(x!=1)
				A.push_back(x);
    		if(y!=1)
				A.push_back(y);
    	}
    }
    for(int i=2;i<=b/i;i++){
    	if(b%i==0){
    		int x=i,y=b/i;
    		if(x!=1)
				B.push_back(x);
    		if(y!=1)
				B.push_back(y);
    	}
    }
    int ans = lcm(a,b);
    for(auto &x:A){
    	int now=lcm(a,x)+lcm(b,x);
    	ans=min(ans,now);
    	for(auto &y:B){
    		int now1=lcm(a,x)+lcm(x,y)+lcm(y,b);
    		int now2=lcm(a,x)+lcm(x,2)+lcm(y,2)+lcm(y,b);
    		ans=min({ans,now1,now2});
    	}
    }
    for(auto &x:B){
    	int now=lcm(a,x)+lcm(b,x);
    	ans=min(ans,now);
    	for(auto &y:A){
    		int now1=lcm(a,x)+lcm(x,y)+lcm(y,b);
    		int now2=lcm(a,x)+lcm(x,2)+lcm(y,2)+lcm(y,b);
    		ans=min({ans,now1,now2});
    	}
    }
    cout<<ans<<endl;
    return;
}
int main(){
	int T;
	cin>>T;
	while(T--)
		solve();
	return 0;
}

友情提醒:不要Ctrl C+Ctrl V

  • 23
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值