首页 > 编程语言 >湖南科技大学2024年计算机程序设计新生赛题解

湖南科技大学2024年计算机程序设计新生赛题解

时间:2024-12-24 15:43:53浏览次数:4  
标签:int 题解 ll long 2024 程序设计 using 代码 奶龙

@

目录

前言

这次比赛通过2-3题的人占大部分。按照过题人数来看,难度是B<A<C<D<E<F<G。整体来看这次题目的代码量都不是特别大,大部分题目的代码在30-40行,E题模拟也只有60多行。

下面是我的题解,如果题解有不懂、错误或者有更好的方法可以评论或者私信交流一下

前置知识补充

题解使用的语言是c++,但是基本和 c 语言一样,与 c 语言相比主要就是输入和输出有一点区别,如有其他的c++内容代码注释会有解释,有 c 语言基础应该是看得懂的。

下面我来说一下c++的输入和输出

//以一个 int 类型的数据来举例
int a;
cin>>a; //c++输入
scanf("%d",&a); //c语言输入

cout<<a<<'\n'; //c++输出
printf("%d\n",a); //c语言输出

// 下面是关闭同步流,可以去查一下更详细的解释
// 简单来说就是提高c++输入和输出的效率
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);

好了,接下来来看题目吧

问题 A: 珂朵莉

解题思路

A题求通项公式,我感觉是一个数学题,但是我数学能力有限,求不出通项公式。所以我是找规律找出来的。

根据题目给的 a1=4 ,还有递推公式:
an+1 = ( 4 * an -9 ) / ( an - 2 );
可以列出前6个分别为:4/1,7/2,10/3,13/4,16/5,19/6.

相信这里规律已经很明显了。
我们可以得出通项公式为:an = ( 3 * n + 1 ) / n ;
通项公式出来了,那代码就很简单了

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 9;
void solve()
{
	int n;
	cin>>n;
	// x 为分子   y 为分母
	int x=3*n+1,y=n;
	cout<<x<<' '<<y<<'\n';
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int _ = 1;
    //多组数据输入
    cin >> _;
    while (_--) solve();
    return 0;
}

问题 B: 可莉的烦恼

解题思路

这题就是把题目的式子化简,几次平方差公式和完全平方公式就可以化简,这里我就不演示了,化简出来的式子是:
y2 + 2xy + 2x4 + x2 - z =0 ;
这是一个一元二次方程,直接用求根公式求解

好了,看代码吧

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 9;
void solve()
{
	int x,z;
	cin>>x>>z;
	// 计算 a b c 的值
	int a=1,b=2*x,c=2*x*x*x*x+x*x-z;
	// 判断是否无解
	if(b*b-4*a*c<0)
	{
		cout<<"No Solution!"<<'\n';
		return;
	}
	double y1=(-b+sqrt(b*b-4*a*c))/2*a;
	double y2=(-b-sqrt(b*b-4*a*c))/2*a;
	// 考虑两个解相等(相当于只有一个解)的情况
	if(y1==y2) cout<<y1<<'\n';
	else cout<<y1+y2<<'\n';
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int _ = 1;
    //cin >> _;
    while (_--) solve();
    return 0;
}

问题 C: 小A的画

解题思路

这题重点就是:当 0 和 1 相邻时,我们只能对其中一个进行染色。我们通过逆向思维,先把所有的 0 和 1 都上色。然后遍历整个字符串,每碰到一对相邻的 0 和 1 我们就取消上色其中的一个。

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 9;

void solve()
{
	// string 是字符串类型
	// 如果输入 n 个字符对应的下标从 0到n-1
	// 这里直接用char数组也行
	string s;
	cin>>s;
	// 获取字符串s的长度
	int n=s.length();
	// 默认对所有 0 和 1 上色
	int ans=n;
	// 遍历整个字符串,注意从1开始,不然i-1会越界
	for(int i=1;i<n;i++)
	{
		// 判断 0 和 1 是否相邻
		if(s[i]!=s[i-1])
		{
			// 对 0 和 1 其中一个取消上色
			ans--;
			// 这里i++是因为:当前i和i-1位已经构成了一对01
			// i不能在后面再使用,所以i++
			i++;
		}
	}
	cout<<ans<<'\n';
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int _ = 1;
    //cin >> _;
    while (_--) solve();
    return 0;
}

问题 D: KMP自动机fail树dfs序建可持久化线段树

解题思路

这题就是kmp的模板题,但是数据不是很大,没学过kmp算法的也可以二分做。这里我的解法是kmp,如果有需要二分解法的我后续再更新。

题目要求:字符串的最小周期
即求:字符串长度 - 最长的相等的真前缀与真后缀的长度。
kmp算法可以 O(n) 的时间复杂度求出整个最长的长度。
二分的时间复杂度是 O(nlogn) 。

下面看代码吧

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 9;
int nex[N];
void solve()
{
	int n;
	string s;
	cin>>n>>s;
	// 让s的下标从 0到n-1 改成 1到n
	s=" "+s;
	// mx用来记录最长的真前后缀相等的长度
	int mx=0;
	// kmp模板 nex数组记录最长前后缀长度
	for(int i=2,j=0;i<=n;i++)
	{
		while(j&&s[i]!=s[j+1]) j=nex[j];
	   	if(s[i]==s[j+1]) j++;
	   	nex[i]=j;
	   	// 更新mx的值
	   	mx=max(mx,nex[i]);
   	}
   	//输出最小周期
   	cout<<n-mx<<'\n';
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int _ = 1;
    //cin >> _;
    while (_--) solve();
    return 0;
}

问题 E: 谜题:结局

解题思路

这题就是根据题目的意思模拟操作就行了,具体的细节看代码的注释吧。

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 9;
int n,m;
// 定义一个结构体储存随从的属性
struct Q
{
	// idx 表示编号  a 表示攻击力  b 表示血量
	int a,b,idx;
	// 自定义排序规则
	bool operator < (const Q&x)const
	{
		if(a!=x.a) return a<x.a;
		if(b!=x.b) return b<x.b;
		return idx<x.idx;
	}
}t[N];

void solve()
{
	cin>>n>>m;
	// 输入随从数据
	for(int i=1;i<=n;i++)
	{
		cin>>t[i].a>>t[i].b;
		// 初始化编号
		t[i].idx=i;
	}
	while(m--)
	{
		int op;
		cin>>op;
		if(op==1)
		{
			int x,y;
			// 在末尾增加一个随从,记得初始化编号
			++n;
			t[n].idx=n;
			cin>>t[n].a>>t[n].b>>x>>y;
			// 交换下标为 x和y 的随从属性
			// 可以使用swap函数
			// 注意编号不用交换
			swap(t[x],t[y]);
			// 交换两次编号,相当于没有交换
			swap(t[x].idx,t[y].idx);
		}
		else 
		{
			int x,y;
			cin>>x>>y;
			// 下标为 x和y 的随从相互攻击
			t[x].b-=t[y].a;
			t[y].b-=t[x].a;
		}
	}
	// 排序
	sort(t+1,t+1+n);
	int k=0;
	// 遍历整个数组,计算有多少随从还活着
	for(int i=1;i<=n;i++)
	{
		if(t[i].b>0) k++;
	}
	cout<<k<<'\n';
	// 输出还活着的随从的编号
	for(int i=1;i<=n;i++)
	{
		if(t[i].b>0) cout<<t[i].idx<<' ';
	}
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int _ = 1;
    //cin >> _;
    while (_--) solve();
    return 0;
}

问题 F: 奶龙列阵(easy version)

解题思路

根据题目意思我们可以得出:奇数排的所有奶龙举的手相同,偶数排的所有奶龙举的手相同。

奇数排的奶龙数量依次是:1,3,5,7,9,11,13
偶数排的奶龙数量依次是:2,4,8,10,12,14,16

可以得出:
奇数排的通项公式:an = 2n - 1 ,
求和公式:Sn = n2 ;

偶数排的通项公式:an = 2n ,
求和公式:Sn = n(n+1) ;

我们可以对排数进行二分,再确定奇数排和偶数排的数量,从而可以算出各自需要的奶龙数量,最后判断是否能按题目的要求列阵。

细节看代码注释

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 9;
// 感觉数据挺大的还是开ll好一点
ll n,a,b,c;
bool check(ll mid)
{
	// x 为奇数排的数量  y 为偶数排的数量 
	ll x=mid/2+(mid%2),y=mid/2;
	// sum1 为奇数排需要的奶龙数量  sum2 为偶数排
	ll sum1=x*x,sum2=y*(y+1);
	// 如果奶龙数量大于所有奶龙,则不符合题意
	if(sum1+sum2>n) return false;
	
	// 假设奇数排举左手 偶数排举右手
	// 注意d1 d2 不能小于 0
	ll d1=sum1-a,d2=sum2-b;
	d1=max(d1,0LL);d2=max(d2,0LL);
	// 符合题意
	if(d1+d2<=c) return true;
	
	// 假设奇数排举右手 偶数排举左手
	d1=sum2-a,d2=sum1-b;
	d1=max(d1,0LL);d2=max(d2,0LL);
	if(d1+d2<=c) return true;
	// 如果上述没有符合题意的情况,则不符合题意
	return false;
}
void solve()
{
	cin>>n>>a>>b>>c;
	// 确定排数的左右边界,最少为 0 排,最多不超过 n 排
	ll l=0,r=n+1;
	// 二分
	while(l+1!=r)
	{
		ll mid=(l+r)>>1;
		// 判断是否符合题意
		if(check(mid)) l=mid;
		else r=mid; 
	}
	// 输出答案,二分中始终保证 l 排符合题目的要求
	cout<<l<<'\n';
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int _ = 1;
    //cin >> _;
    while (_--) solve();
    return 0;
}

问题 G: 小A的密码

解题思路

这道题是一个找规律题,但是对于无解的情况我感觉我的解释可能不那么容易看懂。先说结论当 n<=4 或者 n=6 的时候是无解的。

我们从题目给的样例来看吧

长度为 5:21200
我们来考虑长度为 6,我们先不管这个密码正不正确,直接在长度为 5 的基础上最后加一个 0 ,同时下标为 0 的地方数字加一,得到的密码就是:321000,由于第一个是 3,那么下标为3的地方数字应该为 1,就是:321100,但是如果把下标为 3 处的 0 修改成 1 那么下标为 0 处的数字应该减 1 ,可以重复此过程,但是无论如何都得不到正确的密码,所以长度为 6 无解。

还有 n<=4 的情况,大家可以自己去尝试,也是无解的。

接下来我们再考虑其他的
长度为 7:在上面我们得到了一个长度为 6 的错误的密码:321100,在这个基础上我们只需要在最后加一个 0 就是一个长度为 7 的正确的密码:3211000

我们再往后写几个:
长度为 7:3211000
长度为 8:42101000
长度为 9:521001000
长度为 10:6210001000
长度为 11:72100001000

这里规律已经很明显了,第一位就是 n-4 ,第二三位分别为 2,1 ,然后倒数第四位是 1 ,其他的全是 0 ,还有一个长度为 5 的不符合这个规律,我们可以直接将它特判掉。

ok,看代码吧

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 9;

void solve()
{
	int n;
	cin>>n;
	// 无解的情况
	if(n<=4||n==6) 
	{
		cout<<-1<<'\n';
		return;
	}
	// 特判长度为 5 的情况
	if(n==5)
	{
		cout<<"2 1 2 0 0\n";
		return;
	}
	// 根据规律输出密码
	cout<<n-4<<" 2 1 ";
	for(int i=3;i<n;i++)
	{
		if(i==n-4) cout<<1<<' ';
		else cout<<0<<' ';
	}
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int _ = 1;
    //cin >> _;
    while (_--) solve();
    return 0;
}

问题 H: 谜题:铸币

解题思路

这题思路很简单,就是分六种情况:酒馆等级为1-6级购买随从所需的铸币期望。然后在这六种情况中取最小值。

虽然思路很简单但是代码实现还是有一定难度的,我们直接来看代码吧

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 9;
int x;
double p[10][10];
void solve()
{
	cin>>x;
	for(int i=1;i<=6;i++)
		for(int j=1;j<=6;j++) 
		{
			cin>>p[i][j];
			// 直接预处理让 p 存储刷到几星随从的概率
			p[i][j]/=1000;
		}
	// 答案初始化为一个最大值,因为后面要取小
	double ans=1e9;
	// now 记录固定消费
	// 初始化为 3 因为购买一个随从要花费 3 铸币
	double now=3,p1;
	// 循环六次,分别表示酒馆等级 1-6
	for(int i=1;i<=6;i++)
	{
		// 如果酒馆等级为 i 时刷出 x 星的随从概率大于 0 
		if(p[i][x]>0)
		{
			// p1 记录刷新的随从中,没有一个是 x 星的概率
			// i 等级的酒馆刷出 x 星的随从概率为 p[i][x] 
			// 所以不是 x 星随从的概率为 1-p[i][x]
			// i 等级酒馆每次能刷出 i+1 个随从
			p1=pow(1-p[i][x],i+1);
			// 刷新的次数期望为 1/(1-p1),每次刷新需要 1 铸币
			// 所需的消费为:刷新所需的铸币期望 + 固定消费(now)
			// 更新ans
			ans=min(ans,1/(1-p1)+now);
		}
		// 下面为升级酒馆所需的花费
		if(i==1) now+=5;
		if(i==2) now+=7;
		if(i==3) now+=8;
		if(i==4) now+=9;
		if(i==5) now+=11;
	}
	// 设置精度为小数点后 3 位
	// 类似于 c 语言输出中的 %.3f
	cout<<fixed<<setprecision(3)<<ans<<'\n';
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int _ = 1;
    //cin >> _;
    while (_--) solve();
    return 0;
}

问题 I: 小Z的完全平方数

解题思路

这题是要判断 n 个数相乘最后的结果是不是一个完全平方数。

本质上是一个质因数分解的题目,即对 n 个数进行质因数分解,最后每个质因数的次幂和要为偶数,则这 n 个数的积为完全平方数。

质因数分解:任何一个正整数都可以唯一地分解成若干质数的乘积。

但是考虑到数据范围:1<=n<=1000,1<=xi<=1e18 。
对 n 个数进行质因数分解时间复杂度太高,因为我们质因数分解前要先筛出所有的质数,x 的数量级达到了1e18,在筛选质数的时候就已经超时了。

转变一下思路:我们每次选择两个数,求两个数的最大公约数,然后这两个数同时约去最大公约数,这里最大公约数被约去了两次,即偶数次。最后我们只需要判断这 n 个数它本身是不是一个完全平方数,如果有一个不是,那么结果就不是一个完全平方数。

说了那么多,来看代码吧

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 9;
// 数据很大 开ll
ll n,a[N];
void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	// 排序,这里排不排序都行
	sort(a+1,a+1+n);
	// 每次选择下标为 i和j 的数
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			// 注意 i和j 不能相等
			// 相等相当于我们只选择了一个数
			if(j==i) continue;
			// __gcd() 函数是求最大公约数,是c++库里面的
			// 可以直接使用
			ll x=__gcd(a[i],a[j]);
			a[i]/=x;a[j]/=x;
		}
	}
	// 判断 n 个数本身是否为完全平方数
	for(int i=1;i<=n;i++) 
	{
		ll k=sqrt(a[i]);
		// 有一个不是直接输出 No
		if(k*k!=a[i])
		{
			cout<<"No\n";
			return;
		}
	}
	// n 个数都是完全平方数 输出Yes
	cout<<"Yes\n";
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int _ = 1;
    cin >> _;
    while (_--) solve();
    return 0;
}

问题 J: 奶龙列阵(hard version)

解题思路

首先感谢一下陌队提名我为奶龙大王,没想到居然是压轴题。

建议先看一下前面 F 题的题解再来看这个。

这题和 F 题的区别在:

  1. 列阵方式不一样,F 题的第 k 排有k个奶龙,这题的第 k 排有 2k-1个奶龙。
  2. 数据大小不一样,F 题只有一组数据,这题有 T 组数据(T <= 1000000)。

和 F 题同样的分析:
奇数排的奶龙数量依次是:1,5,9,13,17,21,25
偶数排的奶龙数量依次是:3,7,11,15,19,23,27

可以得出:
奇数排的通项公式:an = 4n - 3 ,
求和公式:Sn = n(2n - 1) ;

偶数排的通项公式:an = 4n - 1 ,
求和公式:Sn = n(2n + 1) ;

思路和 F 是一样的只不过是最后的通项公式和求和公式不一样

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 9;
// 感觉数据挺大的还是开ll好一点
ll n,a,b,c;
bool check(ll mid)
{
	// x 为奇数排的数量  y 为偶数排的数量 
	ll x=mid/2+(mid%2),y=mid/2;
	// sum1 为奇数排需要的奶龙数量  sum2 为偶数排
	ll sum1=x*(2*x-1),sum2=y*(2*y+1);
	// 如果奶龙数量大于所有奶龙,则不符合题意
	if(sum1+sum2>n) return false;
	
	// 假设奇数排举左手 偶数排举右手
	// 注意d1 d2 不能小于 0
	ll d1=sum1-a,d2=sum2-b;
	d1=max(d1,0LL);d2=max(d2,0LL);
	// 符合题意
	if(d1+d2<=c) return true;
	
	// 假设奇数排举右手 偶数排举左手
	d1=sum2-a,d2=sum1-b;
	d1=max(d1,0LL);d2=max(d2,0LL);
	if(d1+d2<=c) return true;
	// 如果上述没有符合题意的情况,则不符合题意
	return false;
}
void solve()
{
	cin>>a>>b>>c;
	n=a+b+c;
	// 确定排数的左右边界,最少为 0 排,最多不超过 n 排
	ll l=0,r=n+1;
	// 二分
	while(l+1!=r)
	{
		ll mid=(l+r)>>1;
		// 判断是否符合题意
		if(check(mid)) l=mid;
		else r=mid; 
	}
	// 输出答案,二分中始终保证 l 排符合题目的要求
	cout<<l<<'\n';
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int _ = 1;
    // 多组数据输入
    cin >> _;
    while (_--) solve();
    return 0;
}

结语

想来想去还是记录一下今年的新生赛吧,毕竟明年还是个未知数,也希望明年我还有能力写题解吧。

最后祝大家天天开心,早日脱单٩(๑^ o ^๑)۶

标签:int,题解,ll,long,2024,程序设计,using,代码,奶龙
From: https://www.cnblogs.com/jin1/p/18627817

相关文章

  • IDEA 2024.3.1.1完整的安装教程(附激活,常见问题处理)
    卸载老版本IDEA首先,如果小伙伴的电脑上有安装老版本的IDEA,需要将其彻底卸载掉,如下所示(没有安装则不用管,直接安装即可):TIP:如果你之前使用过本站提供的 激活到2025年版本脚本,需要执行对应卸载脚本/适用2024版本/JetBrains2023最新全家桶/jetbra/scripts/uninstall-a......
  • [BZOJ2741][FOTILE模拟赛] L 题解
    相当好的题目,虽然和我前几天出的题重了qwq。\(lmx\)是我们的红太阳,没有他我们就会死!!!暴力枚举一个端点,然后用可持久化\(01\Trie\)或者离线\(Trie\)(当然这题用不了,但不强制在线的话是可以的)得到答案。时间复杂度\(O(nm\logn)\),过不了,考虑优化。红太阳\(lmx\)曾经说过:当......
  • 2024年度开源低代码大排名!这几个遥遥领先!
    近年来,低代码及无代码平台越来越多,数量不断攀升。在众多此类平台中,开源的低代码与无代码平台脱颖而出,每一个平台均具备独一无二的优势、特定的适用场景以及专属的用户群体。下面让我们来看看都有哪些优秀的平台吧。JeecgBoot特点:JeecgBoot是一款基于BPM的低代码平台!前后端分......
  • umount: /xxx: target is busy问题解决
    在卸载文件系统的时候,提示umount:/tqls_system:targetisbusy,表示挂载的文件系统正在被使用。要卸载文件系统,必须结束使用文件或者目录的进程`fuser`命令用于查看使用特定文件或者文件系统的进程ID主要参数如下:```-mNAME,--mountNAME NAMEspecifiesafileonamou......
  • 2024年项目管理软件排行榜:哪款最适合你?
    在项目管理领域,选择合适的软件工具是确保项目成功的关键因素之一。随着技术的不断进步,市场上涌现出众多功能强大、易于使用的项目管理软件。本文将为您详细介绍2024年最受欢迎的项目管理软件,帮助您找到最适合您团队需求的工具。禅道项目管理软件禅道项目管理软件是一款开源的项......
  • 2024网络安全学习路线 非常详细 推荐学习
    关键词:网络安全入门、渗透测试学习、零基础学安全、网络安全学习路线首先咱们聊聊,学习网络安全方向通常会有哪些问题1、打基础时间太长学基础花费很长时间,光语言都有几门,有些人会倒在学习linux系统及命令的路上,更多的人会倒在学习语言上;2、知识点掌握程度不清楚对于......
  • 2024年12月中国数据库排行榜:群雄竞逐显风采,GoldenDB摘探花
    2024年末的墨天轮中国数据库排行榜如期发布。回顾整年,榜单持续波动:OceanBase与PolarDB交替登顶,前三甲的位置也不断迎来新晋挑战者。在最新一期的榜单中,GoldenDB凭借技术创新与市场积淀成功跃升前三,openGauss与TDSQL出现了位次调整,其他产品也在不断沉淀与创新中激发出新的动力。可......
  • (2024最新毕设合集)基于SpringBoot的小说在线阅读网咖+86615|可做计算机毕业设计JAVA、P
    目 录摘要1绪论1.1 选题背景1.2研究内容1.3本文的组织结构2相关技术介绍2.1MySQL数据库2.2Java编程语言2.3SpringBoot框架介绍3 系统需求分析与设计3.1可行性分析3.1.1技术可行性分析3.1.2经济可行性分析3.1.3法律可行性分析3.2需......
  • USACO计算机竞赛2024-2025即将开考 报名方式、考点内容全解析
    USACO计算机竞赛2024-2025即将开考报名方式、考点内容全解析 USACO竞赛已经有30多年举办历史,吸引了全球众多计算机编程爱好者参赛,且比赛门槛低,中小学都可以参赛!如果学生有足够的算法能力,那么很有可能在USACO竞赛中拿到名次,助力名校申请。查看以往MIT录取学生简历,我们......
  • Yolov8-pose关键点检测:轻量化注意力 | 单头注意力模块,并行结合全局和局部信息提高准确
      ......