2024全国大学生高新技术竞赛——算法智星挑战赛

193 阅读7分钟

第一题 手机

7a1c6ceea1f988bae8702129cfe95f6.png

样例

i have a dream

思路

这题考点就是怎么存储手机键盘,这里我选择用一个二维字符串来存储,一维存储每一个键。

image.png

code

#include<bits/stdc++.h>
using namespace std;
//string  str = "abc def ghi jkl mno pqrs tuv wxzy";

const string str[] = { {' '}, {"abc"},{"def"},{"ghi"},{"jkl"},{"mno"},{"pqrs"},{"tuv"} ,{"wxyz"},{"*"},{"#"}};

int cnt;
int main()
{
	string s; getline(cin,s);

	for (int i = 0; i < s.size(); i++)
	{
		for (int j=0;j<13;j++)
		{
			for (int k = 0; k < str[j].size(); k++)
			{
				if (s[i] == str[j][k])
				{
					cnt += k+1;
					break;
				}
			}
		}
		//if (s[i] == ' ')cnt++;
	}

	cout << cnt << endl;
	return 0;
}

image.png

第二题 幸运树

b54f0e804f446510f974193d492b1c1.png

样例

2
16347
76344

解题思路

纯模拟,按照题意模拟即可。

//第二题
#include<bits/stdc++.h>
using namespace std;
#define int long long
int Sum(int x)
{
	int sum = 0;
	while (x)
	{
		sum += x % 10;
		x /= 10;
	}
	return sum;
}


int solve(int temp)
{
	int sum = 0;
	//把数乘以7
	temp *= 7;
	while (1)
	{
		if (temp > 9)
		{
			sum = Sum(temp);
		}
		else
		{
			return  temp;
		}

		temp = sum;
	}
}
signed main()
{
	cin.tie(nullptr)->sync_with_stdio(false);
	int t; cin >> t;
	while (t--)
	{
		string x; cin >> x;
		reverse(x.begin(), x.end());
		string s;
		for (int i = 0; i < x.size(); i++)  //因为下标从0开始,所以题目中的对奇数位进行操作这里是对偶数位进行操作
		{
			if (i % 2 == 0)
			{
				int t = solve(x[i] - '0');
				//cout << "x[i]: " << x[i] <<" "<<"t: "<<t<< endl;
				stringstream ss;
				ss << t;
				ss >> x[i];
			}
		}

		stringstream ss;
		ss << x;
		int num;
		ss >> num;
		int ans = Sum(num);
		if (ans % 8 == 0)cout << "T" << endl;
		else cout << "F" << endl;

	}
	return 0;
}

image.png

第三题 a+b problem

379b8cea7a9be50455d817c3fd7f928.png

思路

就是考大数相加

样例

1
1
1001
9099

写了一坨狗屎:

code

#include<bits/stdc++.h>
using namespace std;
#define int long long
void slove(string a, string b)
{
	int jin = 0;
	string sum(a);
	
	for (int i = 0; i < a.size(); i++)
	{
	 int num= (a[i] - '0') + (b[i] - '0') + jin;
		
	 //   stringstream ss;
		//string str;
		//ss<<num;
		//ss >> str;
		//
		if (num > 9)
		{
			sum[i] = num % 10;
			jin +=1;
		}
		else
		{
			
			stringstream ss;
			ss << num;
			ss >> sum;
		}
	}

	//cout << sum.size() << endl;
	for (int i = 0; i < sum.size(); i++)
	{
		cout << sum[i]<<" ";
	}
}

signed main()
{
	cin.tie(nullptr)->sync_with_stdio(false);
	string a, b;
	cin >> a >> b;

	//补0

	if (a.size() < b.size())
		a.append(b.size() - a.size(), '0');
	else
		a.append(a.size() - b.size(), '0');
	reverse(a.begin(), a.end());
	reverse(b.begin(), b.end());

	//开始大数相加
    slove(a, b);
	return 0;
}

正确代码:

#include<bits/stdc++.h>
using namespace std;
vector<int> sum(vector<int>& a, vector<int>& b)//引用是为了提高效率,尽可能不调用拷贝构造
{
	vector<int>c;
	int t = 0;
	for (int i = 0; i < a.size() || i < b.size(); i++)
	{
		if (i < a.size())t += a[i];
		if (i < b.size())t += b[i];
	    
		c.push_back(t%10); //比如个位数 5+1=6 6/10=0,说明不用进位  如果9+9=18,18/10=1,说明需要进1位
		t /= 10;
	}
	if (t)c.push_back(1);
   
    return c;
}

int main()
{
	string a, b; cin >> a >> b;

	vector<int>v1, v2;
	
	for (int i = a.size() - 1; i >= 0; i--)
		v1.push_back(a[i] - '0');

	for (int i = b.size() - 1; i >= 0; i--)
		v2.push_back(b[i] - '0');

	vector<int> c=sum(v1,v2);

	for (int i = c.size() - 1; i >= 0; i--)
		cout << c[i];
	return 0;
}

第四题 求a的b次方

a9b6e1845a15715ece554613d51cb39.png

样例

2 3

样例

7 2011

思路

我刚开始用的快速幂,过了第一个样例,第二个样例就溢出了

#include<bits/stdc++.h>
using namespace std;
#define int long long

int qmi(int a,int b)
{
	int res = 1;
	while (b)  //b如果不为0
	{
		res = res * a ;	
		
		a = a * a;  //底数倍增
		b >>= 1;    //指数右移
	}

	return res;
}
signed main()
{
		int a, b; cin >> a >> b;
		int ans = qmi(a, b);
		//cout << ans<<endl;
		string str = to_string(ans);

		while (str.size() < 3)str = '0' + str;

		for (int i = 0; i < 3; i++)
		{
			cout << str[i];
		}
	return 0;
}

image.png

我以为是b太大了,long long也存不下,要用字符串快速幂,类似于这题:2024年第八场蓝桥杯小白赛 djwcb 知识点:快速幂 - 掘金 (juejin.cn)

但是实际上b只有10000,是可以存下的,错误的原因是板子默错了,痛失一道题:

#include<bits/stdc++.h>
using namespace std;
#define int long long

int qmi(int a, int b,int p)
{
	int res = 1;
	while (b)  //b如果不为0
	{
		if(b&1)res = res * a%p;

		a = a * a%p;  //底数倍增
		b >>= 1;    //指数右移
	}

	return res;
}
signed main()
{
	int a, b; cin >> a >> b;
	int ans = qmi(a, b,1000);
	//cout << ans<<endl;
	string str = to_string(ans);

	while (str.size() < 3)str = '0' + str;

	for (int i = 0; i < 3; i++)
	{
		cout << str[i];
	}
	return 0;
}

image.png

第五题 赛前准备

image.png

思路

要满足K次兴奋,首先k不能大于n,因为总共就n个数,不可能有k+1次兴奋。

k如果为0的话就是全部升序,k如果为n的话就是全部降序。

想要兴奋k次,就让前面面1全部升序,直到k次,后面全部降序即可。

样例

image.png

3
6 2
5 4
5 0

code


#include<bits/stdc++.h>
using namespace std;

int main()
{
	int t; cin >> t;
	while (t--)
	{
		int n, k; cin >> n >> k;

		int l = 1, r = n;
		for (int i = 1; i <= k; i++)cout<<l++;
		for (int j = k + 1; j <=n; j++)cout << r--;
		cout << endl;
	}
	return 0;
}

第六题 最小乘积

image.png

思想 只需要记录一下正数,负数,0,的数量即可。

如果存在 0,显然不管怎么操作最后乘积都是0,则不需要操作。

如果不存在 0,若 负数 有奇数个,那么最终乘积为负数,不需要修改。

若 负数 有偶数个,那么乘积一定正数,任意一个改成0。

code

#include<bits/stdc++.h>
using namespace std;
int n; 


void solve()
{ 
	int xiao = 0, da = 0, deng = 0;
	cin >> n;
	for(int i=0;i<n;i++)
	{
		int x; cin >> x;
		if (x < 0)xiao++;
		else if (x == 0) deng++;
		else da++;
	}
	//如果存在一个0,结果一定为0
	if (deng >= 1) cout << 0 << endl;
	else
	{
		if (xiao % 2) //奇数个负数,最后乘积为负数
			cout << 0 << endl;
		else  //偶数个负数,乘积为正数,把任意改为0
		{

			cout << 1 << endl;
			cout << 1 << " " << 0 << endl;
		}
	}

}
int main()
{
	int t = 1; cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}

第七题 探险

image.png

思路 这道题类似于20204年第三场小白赛 怪兽突击 知识点:贪心 - 掘金 (juejin.cn)

小理一定在某个洞穴停下,剩下的次数全部用来反复进入前面进入过的洞穴,且反复进入的洞穴一定是同一个,经验值最大的那一个。

那么只需要枚举所有情况就可以了。

code

#include<bits/stdc++.h>
using namespace std;
#define int long long

int n, k;

void solve()
{
	cin >> n >> k;
	vector<int> a(n + 1), b(n + 1);
	for (int i = 1; i <= n; i++)cin >> a[i];
	for (int j = 1; j <= n; j++)cin >> b[j];
    
	//枚举每个洞穴经历k次之后的经验值
	//所有经验值里面取一个最大值
	int f = 0, res = 0, ans = 0;
	for (int i = 1; i <= min(n, k); i++)
	{
		int remain = k - i;
		f += a[i];

		//剩下的k-1次全部打当前洞穴
		res = max(res, b[i]);
		ans = max(ans,remain*res+f);
	}
	cout << ans << endl;
}
signed main()
{
	int t; cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}

第十题 去除没有吸引力的配对

image.png

思路

从前往后遍历字符串s,如果两个字符不一样那就可以删除,我们把这两个字符标记为1,然后把没有标记为1的字符加入到temp字符串里,用temp字符串更新s字符串。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10;
int flag[N];
int n;
string temp;

int solve(string s)
{
	while (1)
	{
		for (int i = 0; i < s.size() - 1; i++)
		{
			if (s[i] != s[i + 1] && flag[i] == 0)
			{
				flag[i] = flag[i + 1] = 1;
			}
		}
	   

		for (int i = 0; i < s.size(); i++)
		{
			if (flag[i] == 0)
			{
               temp.push_back(s[i]);
			}
		}
		
		
		cout << temp << endl;
		s = temp;
		temp.clear();
		memset(flag,0,sizeof flag);

		if (s.size() == 0)break;

		int cnt = 0;
		for (int i = 0; i < s.size()-1; i++)
		{
			if (s[i] != s[i + 1])cnt++;
		}
		if (cnt == 0)break;
	}
	return s.size();
}
signed main()
{
	int t; cin >> t;
	while (t--)
	{
		 cin >> n;
		string s; cin >> s;
		cout <<"答案:"<< solve(s) << endl;
	}
	return 0;
}

image.png

代码存在的问题是只考虑了从前向后依次遍历字符串,比如:

dabbb

'd'和'a'不一样删除,变为:

bbb

不能再删除了。但是实际上,这个顺序并不一定是从前向后遍历的,比如可以先把'a'和'b'删除,变为:

abb

然后再把a,b删除,还剩:

b

正解

如果一个数出现的次数最多,且刚好出现的次数为n的一半,那么肯定会有另外一半数与它匹配,最后全部消掉。如果这个数出现的次数超过了一半,因为这个数出现的最多,我们就叫maxn,因为出现的超过了n的一半,所以剩下的数肯定不够与它匹配,那么消除完之后还剩的个数就是maxn-(n-maxn)。否则,出现这个数出现的次数少于n的一半,假设它出现了奇数次,那么消到最后会剩一个,如果它出现的次数为偶数,那么消到最后会全部消完。

#include<bits/stdc++.h>
using namespace std;

int main()
{
	int t; cin >> t;
	while (t--)
	{
		int n; cin >> n;
		string s; cin >> s;
		int cnt[26] = { 0 };
		int maxn = 0;
		for (int i = 0; i < n; i++)
		{
			cnt[s[i] - 'a']++;
			maxn = max(maxn, cnt[s[i] - 'a']);
		}
		if (maxn >= n - maxn)cout << maxn - (n - maxn)<<endl;
		else cout << (n & 1) << endl;
	}
	return 0;
}