SYSU01-Ural Regional School Programming Contest 2014(部分题解)

本文精选了多项算法竞赛题目并提供了详细的解题思路与代码实现,涵盖了字符串处理、数学问题、搜索算法等核心内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A - Adventure Time

题意:给一段长度为n(1<=n<=10^5)的字符串和k(1<=k<=26),字符串由a-z构成。求满足字符串有且仅存在k个互异字母时的最大长度的组合数有多少。

eg:input : ababac 2; output : 5 1

满足字符串有且仅存在k个互异字母的字符串有:aaabb,aaac,bbc,aabb,aac....可得最大长度为5且组合数为1

题解:

统计a-z各个字母在原字串中的个数并排序,最后做个组合数就可以了。细节注意:当字串中不存在k个互异字母时输出n 1即可。

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int main(){
	int chara[26], Count = 0, k; 
	long long  c[30][30];
	string s;
	memset(chara, 0, sizeof(chara));
	memset(c, 0, sizeof(c)); 
	c[0][0]=1;//c的第一维是从m个数中取,第二维是取n个
    for(int i=1;i<=26;i++)
    {
        c[i][0]=1;
        for(int j=1;j<=i && j <= 26;j++) 
        c[i][j]=(c[i-1][j]+c[i-1][j-1]);
    }
	
	cin >> s >> k;
	for(int i = 0; i < s.length(); i++){
		chara[s[i]-97]++;
	}
	sort(chara, chara+26);
	for(int i = 25; i > 25-k; i--){
		Count+=chara[i];
	}
	if(chara[25-k+1] == 0){
		cout << Count << " " << 1 << endl;
		return 0;
	}
	int k1 = 0, k2 = 0;
	for(int i = 25-k+1; i < 26; i++){
		if(chara[25-k+1] == chara[i])k1++;
		else break;
	}
	for(int i = 25-k; i >= 0; i--){
		if(chara[25-k+1] == chara[i])k2++;
		else break;
	}
	cout << Count << " " << c[k1+k2][k1] << endl;
	return 0;
} 

B - Line Fighting

 题意:共有T组测试数据(1<=T<=10),每组数据输入n,k(2<=k<=n<=10^4)。表示n个人,划分成k个队伍。不同队伍选手两两战斗。求最大化的战斗次数。

eg: n = 6  k = 3;

最大化可以划分为每个队伍均有两个人。则战斗次数为A队伍与B队伍有4次对决,A队伍与C队伍有4次对决,B队伍与C队伍有4次对决。合计结果为12次对决。

题解:

每个case尽可能使每个队伍间成员数平均,求战斗数即可

AC代码

#include<iostream>
#include<cstdio>
using namespace std;
int main(){
	int T;
	cin >> T;
	while(T--){
		int n, k;
		cin >> n >> k;
		int x = n/k, y = n%k;
		int z = k-y;
		long long res = 0;
		for(int i = 1; i <= y; i++){
			res += (x+1)*(n-i*(x+1));
		}
		for(int i = y+1; i <= k; i++){
			res += x*(n-(x+1)*y-(i-y)*x);
		}
		cout << res << endl;
	}
	return 0;
}

C - Dean and Schedule

 题意:给出一段长度为n(1<=n<=10^5)的字符串其包含a-z和?,可以对将?修改为a-z任意一个字符。字母存在质量划分,规定a=1,b=2,...,z=26,并且但在字符串偶数位时其质量不计。再给出一个整数k(1<=k<=26)代表字符串中至少存在k个互异的字母,当原字符串不存在k个互异字母,可由修改?使其达到目标。若修改任未能满足要求则输出-1,反之出输出质量最高的字符串。

题解:

遍历一遍字符串统计互异字母个数与?个数的和。若k减去其和为正则无解输出-1,反之有解。

先将字符串填补至k个互异字母(满足偶数位由a开始向上填补,奇数位满足由z向下开始填补)。之后将剩余部分偶数位填入a,奇数位填入z。

AC代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<set>
#include<cmath>
using namespace std;
int main(){
	string s;
	int n, Count = 0;
	queue<int> s1, s2;
	set<char> s3;
	cin >> s >> n;
	for(int i = 0; i < s.length(); i++){
		if(s[i] == '?' && i%2==1){
			s2.push(i);
			Count+=1;
		}
		else if(s[i] == '?'){
			s1.push(i);
			Count+=1;
		}
		else{
			s3.insert(s[i]);
		}
	}
	if(n-(int)s3.size()-Count > 0){ 
		cout << "-1" << endl;
	}
	else if(Count == 0){
		cout << s << endl;
	}
	else{
		char ch1 = 'z', ch2 = 'a';
		int i = 0;
		while(s3.size() < n && ++i){
			if(i%2 && !s1.empty()){
				if(s3.find(ch1) == s3.end()){
					s[s1.front()] = ch1;
					s1.pop();
					s3.insert(ch1);
				}
				ch1--;
			}
			else if(!s2.empty()){
				if(s3.find(ch2) == s3.end()){
					s[s2.front()] = ch2;
					s2.pop();
					s3.insert(ch2);
				}
				ch2++;
			}
		}
                while(!s1.empty()){
                      s[s1.front()] = 'z';
                      s1.pop();
                }
                while(!s2.empty()){
                      s[s2.front()] = 'a';
                      s2.pop();
                }
		cout << s << endl;
	}
	return 0;
} 

D - URCAPL, Episode 1

 题意:一门语言给出一套规则,要求写出该语言的解释器

题解:水题

AC代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn = 1000;
int n, m, k, arr[1000000];
char map[maxn][maxn];
int Set[10000];
void solve(){
	int pos = 1, Pos = 0;//规定1为向右2为向下3为向左4为向上
	int x = 0, y = 0, current = 0, times = 0;
	while(true){
		if(map[x][y] == '>') pos = 1;
		else if(map[x][y] == 'v') pos = 2;
		else if(map[x][y] == '<') pos = 3;
		else if(map[x][y] == '^') pos = 4;
		else if(map[x][y] == '+') current+=1;
		else if(map[x][y] == '-') current-=1;
		else if(map[x][y] == '.'){}
		else if(map[x][y]=='?'){
			if(Pos == k) current = arr[k-1];
			else current = arr[Pos++];
		}
		else if(map[x][y] == '!'){
			cout << current << endl;
			current = 0;
		}
		else if(map[x][y] == '@'){
			if(current==0){
				pos--;
				if(pos == 0) pos = 4;
			}
			else{
				pos++;
				if(pos ==  5) pos = 1;
			}
		}
		else if('A' <= map[x][y] && map[x][y] <= 'Z'){
			swap(Set[map[x][y]], current);
		} 
		else if(map[x][y] == '#'){
			break;
		}
		if(abs(current) > 100000){
			cout << "OVERFLOW ERROR" << endl;
			break;
		}
		if(pos == 1) y+=1;
		else if(pos == 2) x+=1;
		else if(pos == 3) y-=1;
		else if(pos == 4) x-=1;
		if(x<0||y<0||x>=n||y>=m){
			cout << "RUNTIME ERROR" << endl;
			break;
		}
		
		times++;
		if(times >= 1000000){
			cout << "TIME LIMIT EXCEEDED" << endl;
			break;
		}
	} 
}
int main(){
	cin >> n >> m;
	memset(Set, 0, sizeof(Set));
	for(int i = 0; i < n; i++){
		cin >> map[i];
	}
	cin >> k;
	for(int i = 0; i < k; i++)
		cin >> arr[i];
	solve();
	return 0;
} 

E - URCAPL, Episode 2

 题意:由D题给出的语言写出,1+....+n的结果。

弱鸡没写出来

F - Towers of Hanoi Strike Back

 题意:汉诺塔问题。输入n(1<=n<=50),第二行输入长度为n的字符串(仅包含ABC)。ABC分别代表3根柱子。要求盘子按照字符串给出的位置放置,每个盘子的编号为下标+1。所有盘子最开始在A柱子上,求最小移动盘子的步数。

题解:

设ch为未放置规定位置的盘子所在位置。由未放置规定位置的盘子的最底层盘子开始。最底层盘子若要移动到规定位置,其最小步数为2^m(m为底层盘子往上的盘子数目)。注意,若扫描到的盘子已在规定位置则跳过计算。

AC代码

#include<iostream>
#include<cstdio>
using namespace std;
int main(){
	long long res[51];
	long long k = 0;
	int n;
	string str;
	cin >> n >> str;
	res[0] = 0;
	res[1] = 0;
	res[2] = 1;
	for(int i  = 3; i <= 50; i++){
		 res[i] = res[i-1]*2+1;
	}  
	char ch = 'A';
	for(int i = n-1; i >= 0; i--){
		if(str[i]!=ch){
			k+=res[i+1]+1;
			if(ch == 'A' && str[i] == 'B') ch = 'C';
			else if(ch == 'A' && str[i] == 'C') ch = 'B';
			else if(ch == 'B' && str[i] == 'A') ch = 'C';
			else if(ch == 'B' && str[i] == 'C') ch = 'A';
			else if(ch == 'C' && str[i] == 'A') ch = 'B';
			else if(ch == 'C' && str[i] == 'B') ch = 'A';
		}
	}
	cout << k << endl;
	return 0;
}

G - Awesome Backup System

弱鸡还没解出来

H - Overturned Numbers

题意:0、1、8的数翻转180°后仍为本身,6翻转180°后变为9,其余数不能翻转。输入n(1<=n<=99)求n个翻转后连续的序列,仅使用一位整数只补充前导0和两位整数。若没有此序列则输出“Glupenky Pierre”,若存在则输出序列。

题解:

水题。6翻转后变为9且0、1、8翻转后是其本身。则可看出连续序列最大为4。x8、x9、(x+1)0、(x+1)1。

AC代码

#include<iostream>
#include<cstdio>
using namespace std;
int main(){
	char ch[5][3] = {"16","06","68","88","86"};
	int n;
	cin >> n;
	if(n>4)cout << "Glupenky Pierre" << endl;
	else{
		for(int i = 0; i < n; i++){
			cout << ch[i] << " ";
		}
		cout << endl;
	}
	return 0;
}

I - Conspiracy Theory and Rebranding

 题意:给出三角形三条边长度,求出在笛卡尔坐标系下的整数坐标解,若无解则输出-1。

题解:

以原点为三角形的一个坐标点。对其中两条边以原点以其边长为半径画圆。以其两圆上的整数坐标一一判断是否能构成第三边边长,可以则得出结果。否则输出-1。

AC代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
struct rg{
	int x, y;
	rg(int x = 0, int y = 0):x(x),y(y){}
};
int main(){
	int ragc[3], dir[4][2] = {{1,1},{-1,1},{1,-1},{-1,-1}};
	cin >> ragc[0] >> ragc[1] >> ragc[2];
	vector<rg> B;
	B.clear();
	for(int j = 0; j <= ragc[1]; j++){
		long long k1 = 1ll*ragc[1]*ragc[1]-1ll*j*j;
		int k2 = sqrt(k1+0.0);
		if(1ll*k2*k2 != k1)continue;
		B.push_back(rg(j, k2));
	}
	for(int i = 0; i <= ragc[0]; i++){
		long long k1 = 1ll*ragc[0]*ragc[0]-1ll*i*i;
		int k2 = sqrt(k1+0.0);
		if(1ll*k2*k2 != k1) continue;
		for(int j = 0; j < B.size(); j++){
			for(int k = 0; k < 4; k++){
				int x1 = i*dir[k][0], y1 = k2*dir[k][1];
				long long l = 1ll*(x1-B[j].x)*(x1-B[j].x)+1ll*(y1-B[j].y)*(y1-B[j].y);
				if(l != 1ll*ragc[2]*ragc[2])continue;
				cout << "0 0" << endl;
				cout << x1 << " " << y1 << endl;
				cout << B[j].x << " " << B[j].y << endl;
				return 0;
			}
		}
		
	}
	cout << -1 << endl;
	return 0;
} 

J - Devices

题意:求被推荐设备最多且设备价格最低的设备名称。

题解:模拟题,水一下就过了。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct frinds{
	char shebei[30];
	int value;
	int num;
}queue[6];
int main(){
	int k = 0;
	for(int i = 0; i < 6; i++) queue[i].num = 0;
	for(int i = 0; i < 6; i++){
		char a[30], b[30];
		int c, chack = 0;
		cin >> a >> b >> c;
		for(int j = 0; j < k; j++){
			if(!strcmp(b, queue[j].shebei)){
				queue[j].num++;
				queue[j].value = min(queue[j].value, c);
				chack = 1;
				break;
			}
		}
		if(!chack){
			strcpy(queue[k].shebei, b);
			queue[k].num = 1;
			queue[k].value = c;
			k++;
		}
	}
	int value = 1000000, times = 0;
	char res[30] = "";
	for(int i = 0; i < k; i++){
		if(times < queue[i].num){
			memset(res, 0, sizeof(res));
			strcpy(res, queue[i].shebei);
			value = queue[i].value;
			times = queue[i].num;
		}
		else if(times == queue[i].num && value > queue[i].value){
			memset(res, 0, sizeof(res));
			strcpy(res, queue[i].shebei);
			value = queue[i].value;
			times = queue[i].num;
		}
	}
	cout << res << endl;
	return 0;
}

K - Caravans

弱鸡还没解出来

L - Another Dress Rehearsal

 题意:给出A、B、C三个值要求在A区间取一个数,在B区间取一个数,其和为C。

题解:

水题。比赛时想智障想复杂了,用两次二分过了。

AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct frinds{
	char shebei[30];
	int value;
	int num;
}queue[6];
int main(){
	int k = 0;
	for(int i = 0; i < 6; i++) queue[i].num = 0;
	for(int i = 0; i < 6; i++){
		char a[30], b[30];
		int c, chack = 0;
		cin >> a >> b >> c;
		for(int j = 0; j < k; j++){
			if(!strcmp(b, queue[j].shebei)){
				queue[j].num++;
				queue[j].value = min(queue[j].value, c);
				chack = 1;
				break;
			}
		}
		if(!chack){
			strcpy(queue[k].shebei, b);
			queue[k].num = 1;
			queue[k].value = c;
			k++;
		}
	}
	int value = 1000000, times = 0;
	char res[30] = "";
	for(int i = 0; i < k; i++){
		if(times < queue[i].num){
			memset(res, 0, sizeof(res));
			strcpy(res, queue[i].shebei);
			value = queue[i].value;
			times = queue[i].num;
		}
		else if(times == queue[i].num && value > queue[i].value){
			memset(res, 0, sizeof(res));
			strcpy(res, queue[i].shebei);
			value = queue[i].value;
			times = queue[i].num;
		}
	}
	cout << res << endl;
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值