PAT乙级做题经验总结

知识点


字符串转换

char a[] = "abcd";
string data = to_string(sum);


当在某个数字区间内对应结果时,建立数组存储结果可以快速获得结果

//有效存储预先数据
string str[10] = {"ling","yi","er","san","si","wu","liu","qi","ba","jiu"};
int a[] = {2,5,3,1,7,6};
for(int i =0 ;i<6;i++)
	cout<<str[a[i]];


map的合适应用:判断字符串内各字符的出现次数及规律,以及是否只出现特定字符
map内元素无序唯一


大量数据基础下找最大、最小或类似信息,可以不建立数组而是直接进行比较后赋值给相应变量。


数组循环右移的实现原理:倒置

1)整体倒置
2)倒置前n(右移长度)位
3)倒置后半部分

eg:1 2 3 4 5 6 7 8 9 右移3位
1)9 8 7 6 5 4 3 2 1
2)7 8 9 6 5 4 3 2 1
3)7 8 9 1 2 3 4 5 6


对于输入不定长的数据可以用while(cin>>)来处理,在对代码进行测试时可以通过Ctrl+Z来表示输入完成信号,同时对于输入大量信息反向输出可以使用stack来处理。


在结果有两种情况时可以选择用三目运算:1)函数内的return 2)输出时

(x==y)?cout<<“true”:cout<<“false”;
return (x>y)? ture : false;


适当用好swtich可以让代码更加的整洁,大量if else会让代码很乱


判断素数

bool isPrime(int x){
	for(int i=2;i*i<=x;i++)
		if(x%i==0)return false;
	return true;
}


1)判断是否有公约数

bool is(int a,int b){
	return (a!=0) ? is(b%a,a) : b==1;
}

2)求最大公约数:辗转相除法

int max(int a,int b){
	return b == 0 ? a : max(b, a % b);
}

十一
超长数字的计算方法

通过字符串接收string或char[]
加:从低位开始逐一相加,定义一个变量记录进位数
减:从低位开始逐一相减,定义一个变量记录向上一位借的数(先判断是否能借)
乘(个位乘超长数字):低位开始逐一相乘,定义一个变量记录进位数
除(超长数字除个位):高位开始注意相除,定义一个变量记录余数,与下一位数相加继续循环相除

十二
字符串的比较特点:逐一比较,不相等时返回对应位置比较结果,如果等长度全部相同下,则更长的字符串比较大。

该特点可以在日期比较中得到充分的利用:yyyy/mm/dd

十三
string类型字符串大小写转换
transform(begin,end,head,op);
其中op可以为 ::toupper ::tolower

	string s = "aaaBBB";
	string s1,s2;
	transform(s.begin(),s.end(),s1.begin(),::toupper);
	transform(s.begin(),s.end(),s2.begin(),::tolower);

十四
确定数组内符合条件的数据的区间时,需要多次循环遍历数组,找出部分规律可以减少循环时间,避免超时

//1030 完美数列 (25 分)
for(int i=0;i<n;i++){			//eg:确定两个数相除在n范围内的最长数据长度
		for(int j=i+length;j<n;j++){	//数组右侧结尾可以从上次结尾处开始
			if(f[j]/f[i] > p)
				break;
			if(j-i+1>length)
				length = j-i+1;
		}
	}

十五
判断字符串内存在字符
不用s.find(“string”)应该加上不等于空
而用s.find(“string”) != string::npos
string::npos表示字符不存在

十六
一串长字符串中,查找符合字符顺序的组合数量

如果组合数量为3(P,A,T)
遍历字符串依次找到A,将A左侧P数量和右侧T数量的乘积累加求和,就是最终的答案,一层循环就可以解决问题

十七
判断数组内元素小于右侧任意元素,大于左侧任意元素

1)两次循环:
第一次找每一个比前n个元素都大的坐标并记录
第二次找每一个比后n个元素都小的坐标并记录
两次都标记了的坐标即为符合条件的坐标
2)先对数组进行排序,与元素组进行比较,位置相同且大于左侧最大值即符合条件

十八
规范字符串格式
用insert函数insert(site,length,char);
假设length为标准长度
b.insert(b.begin(),length-b.length(),‘0’);

十九
输入重新赋值:
sscanf(赋值变量字符串,“变量类型”,被赋值变量):将字符串以相应类型赋值给变量
sprintf(被赋值变量字符串,“变量类型”,赋值变量) :将变量以相应类型赋值给字符串

	char a[50], b[50];
	double temp;
	scanf("%s", a);			//a = "123456"
    sscanf(a, "%lf", &temp);	//temp = 123456
    sprintf(b, "%.2f",temp);	//b = "123456.00"
	cout<<a<<endl<<b;

二十
字符串转数字

stoi(string)	//转整型	
stod(string)	//转double	
stol(string)	//转long long
stof(string)	//转float

二十一
对于判断元素是否出现的题目,可以使用set来充当容器(set s),set中元素唯一,并且会将set内的元素自动排序,通过find判断是否存在,也可以用map,map无序

	set<int> s;
	s.insert(1);
	s.insert(0);
	if(s.find(3)==s.end())cout<<2;

二十二
交换两变量的值

	swap(type a,type b);

二十三
find的用处

//1)string:
string s = "abcd";
	if(s.find("f")==string::npos)
		cout<<"不存在";

//2)set
set<int> s;
	s.insert(1);
	s.insert(2);
	if(s.find(1)!=s.end())
		cout<<"存在";

//3)vector
vector<int> v;
	v.push_back(1);
	v.push_back(2);
	if(find(v.begin(),v.end(),2)!=v.end())
		cout<<"存在";

二十四
判断类型:

#include <ctype>
isdigit(x);	//数字
isalpha(x);	//字母

二十五
字符串截取:s.substr(start,length),start即开始的坐标点,length即字符串的长度

string s = "123abc456";
string ss = s.substr(3,3);		//s = abc

二十六
二维数组的定义

vector<vector<type>> v;

二十七

判断数组中大于某值的数量有多少:将数组降序排列,依次比较数组元素的大小是否符合,不符合则当时的数组下标即为符合的数量

二十八
输出不同进制的数:

int a = 10;
printf("%o",a);		//八进制
printf("%d",a);		//十进制
printf("%x",a);		//十六进制

二十九
与选项题目相关的问题,abcd选项可以通过二进制来表示(如此可以表示多选题):a:2,b:4,c:8,d:16,这样可以即高效又快速的得到选项,通过把选项相对应的数字加和得到总选项
每个人选择了某个选项可以通过二维数组解决:option[person][question] (例如options[100][10]),其中person表示学生编号,question表示题目编号,赋值a2,b4,c8,d16,并将选项相加
在判断每个学生对应的选项是否符合条件时,可以通过与或非运算(与:&,或:|,非:~,异或:^)
异或运算(^)用来判断是否完全相等
或运算(|)用来判断是否漏选
与运算(&)用来判断错选

三十
当用到索引含有字母的长字符串
可以通过map<string,int>和vector 来将学号和信息绑定,通过map<学号,对应在vecotr中的位置>来找到vector中的位置,
最后如果需要排序什么的就可以直接在vecotr中进行。

三十一
printf输出字符串string用printf("%s",str.c_str());

三十二
substr的妙用
在截取字符串后几位时,可以通过s = s.substr(start); //表示从第start位开始截取到最后,可以用来比较数字小数位是否相同

三十三
关于用给出的长度N和自己求的s.length()的区别
s.size()/s.length的返回值是unsigned int类型
如果说l比k小,你用s.size()所以相减得到的不是负数而是unsigned int类型的一个很大的值,所以会进入for循环,导致了错误,如果你把l改成(int)s.size()是可以答案正确的
还有对于其中的for循环的临界的判断

易错点

审题一定要认真
把条件全部看完后再开始进行做题,对于关键信息要认真阅读


循环右移前应对右移举例进行取余:n%length


结构体内定义string类型数据时可能要用:std::string s;
原因是:可能导入的其它头文件内也包含了string


输入大量数字和字符串时容易出现对应错位其中的string有可能接收到的是’\n’,所以要注意


当输入的数据范围和数组下标对应时:如果存在零则赋初值应该为-1或其它数,数组定义要大于最大值,例如:

学号范围:0~n,
所建立的数组必须为a[n+k],k>0;
赋初值时学号小于零或者大于n。


数字超过范围越界问题:byte->int->double->long long


char *ch类型字符串要用cin输入时,要提前为其分配空间 char *ch = new char[n];


C++中浮点数运算次数在接近无限大时任意出错
因为浮点数在计算机内部的表现是二进制,而部分浮点数转换成二进制后不能完全相对应,只能取无限接近,所以在经过无限次运算后差错放大到明显程度容易出现误差。
解决方法是将对应浮点数小数点后移,取得确定的整数型计算。


对于这种逻辑绕弯多的代码,应该提高每个变量的性质的记忆性,不应该单纯的是a,b,r,c这类,可以是length,grade等赋予意思的变量,逻辑思维能力要提高。


vector的赋值

1)在定义vecotr的时候应该给定空间(vector v(n))后才能直接用cin>>a[i]
2)未赋值空间大小时应该用a.push_back(x);的方式添加元素


转义字符在输出时可能导致输出错误(需要输出则写两个就表示输出:%%表示输出% \\表示输出\)

十一
数据的正负判断
当要进行精确位数时,应该判断负数精确位数是受否进位变成0之后输出类型改变

十二
在使用getline(cin,string)时需要注意:
输入前有输入其它变量,且输入后以\n结尾时要在使用getline(cin,string)前要用getchar()先把\n接收了,否则getline(cin,string)会接收一个空字符串:"\n"

十三
输入中有大量信息但是不一定都要接收
样例中:多组输入,但是当某种条件后不再判断则可以认为之后的输入可以不用接受,直接退出

十四
对于输入二维数组输入及对应位置
for(i){for(j)}中i和j表示的是行和列,而在函数表达式,i往往表示x,j表示y,对应的i为列,j为行,所以很容易搞混
解决方法:输入行列的cin>>H>>L;来表示行列,用i表示行,j表示列。注意:i,j与函数表达式的位置表示区分开

十五
输入链表时,可能出现废节点,所以链表长度不能用输入的节点数代替

十六
输出数字结果可能会对输出类型进行判断:输出数字倒置或者是处理数字时,如果用到了转换成字符串最后输出报错可能需要把字符串转换成数字后在输出

好题复查

1005 继续(3n+1)猜想 (25 分)

卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里,情况稍微有些复杂。
当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数。例如对 n=3 进行验证的时候,我们需要计算 3、5、8、4、2、1,则当我们对 n=5、8、4、2 进行验证的时候,就可以直接判定卡拉兹猜想的真伪,而不需要重复计算,因为这 4 个数已经在验证3的时候遇到过了,我们称 5、8、4、2 是被 3“覆盖”的数。我们称一个数列中的某个数 n 为“关键数”,如果 n 不能被数列中的其他数字所覆盖。
现在给定一系列待验证的数字,我们只需要验证其中的几个关键数,就可以不必再重复验证余下的数字。你的任务就是找出这些关键数字,并按从大到小的顺序输出它们。

输入格式:
每个测试输入包含 1 个测试用例,第 1 行给出一个正整数 K (<100),第 2 行给出 K 个互不相同的待验证的正整数 n (1<n≤100)的值,数字间用空格隔开。

输出格式:
每个测试用例的输出占一行,按从大到小的顺序输出关键数字。数字间用 1 个空格隔开,但一行中最后一个数字后没有空格。

输入样例:

6
3 5 6 7 8 11
结尾无空行

输出样例:

7 6

代码

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
bool cmp(int a,int b){ return a>b; }
int arr[10000];
int main() {
	int n,x,flag = 0;
	vector<int> data;
	cin>>n;
	while(n--){
		cin>>x;
		data.push_back(x);
		while(x!=1){
			if(x%2!=0) x = 3*x+1;
				x /= 2;
			arr[x] = 1;
		}
	}
	sort(data.begin(),data.end(),cmp);
	for(int i=0;i<data.size();i++){
		if(arr[data[i]]==0){
			if(flag==1){
				cout<<" ";
			}
			cout<<data[i];
			flag = 1;
		}
	}
	return 0;
}

总结
对于这种多数据多重循环处理的可以通过建立一个大容量数组,将数据的存在与否用0 1 表示

1015 德才论 (25 分)

宋代史学家司马光在《资治通鉴》中有一段著名的“德才论”:“是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德谓之小人。凡取人之术,苟不得圣人,君子而与之,与其得小人,不若得愚人。”
现给出一批考生的德才分数,请根据司马光的理论给出录取排名。

输入格式:
输入第一行给出 3 个正整数,分别为:N(≤105),即考生总数;L(≥60),为录取最低分数线,即德分和才分均不低于 L 的考生才有资格被考虑录取;H(<100),为优先录取线——德分和才分均不低于此线的被定义为“才德全尽”,此类考生按德才总分从高到低排序;才分不到但德分到线的一类考生属于“德胜才”,也按总分排序,但排在第一类考生之后;德才分均低于 H,但是德分不低于才分的考生属于“才德兼亡”但尚有“德胜才”者,按总分排序,但排在第二类考生之后;其他达到最低线 L 的考生也按总分排序,但排在第三类考生之后。
随后 N 行,每行给出一位考生的信息,包括:准考证号 德分 才分,其中准考证号为 8 位整数,德才分为区间 [0, 100] 内的整数。数字间以空格分隔。

输出格式:
输出第一行首先给出达到最低分数线的考生人数 M,随后 M 行,每行按照输入格式输出一位考生的信息,考生按输入中说明的规则从高到低排序。当某类考生中有多人总分相同时,按其德分降序排列;若德分也并列,则按准考证号的升序输出。

输入样例:

14 60 80
10000001 64 90
10000002 90 60
10000011 85 80
10000003 85 80
10000004 80 85
10000005 82 77
10000006 83 76
10000007 90 78
10000008 75 79
10000009 59 90
10000010 88 45
10000012 80 100
10000013 90 99
10000014 66 60
*结尾无空行

输出样例:

12
10000013 90 99
10000012 80 100
10000003 85 80
10000011 85 80
10000004 80 85
10000007 90 78
10000006 83 76
10000005 82 77
10000002 90 60
10000014 66 60
10000008 75 79
10000001 64 90
*结尾无空行

代码

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef struct node{
	int id,de,cai;
}person;
int N,L,H;
bool compare(person p1,person p2){
	if(p1.cai+p1.de != p2.cai+p2.de)
		return p1.cai+p1.de > p2.cai+p2.de;
	else if(p1.de != p2.de)
		return p1.de > p2.de;
	else
		return p1.id < p2.id;
}
int main() {
	vector<person> people[4];
	int sum=0;
    cin>>N>>L>>H;
    for(int i=0;i<N;i++){
    	person p;
    	cin>>p.id>>p.de>>p.cai;
    	if(p.de>=L && p.cai>=L){
    		sum++;
    		if(p.de >= H && p.cai>=H) people[0].push_back(p);
			else if(p.de >=H && p.cai>=L) people[1].push_back(p);
			else if(p.de >=L && p.cai>=L && p.de >= p.cai) people[2].push_back(p);
			else people[3].push_back(p);
		}
	}
	cout<<sum;
	for(int i=0;i<4;i++){
		sort(people[i].begin(),people[i].end(),compare);
		for(int j=0;j<people[i].size();j++){
			cout<<endl<<people[i][j].id<<" "<<people[i][j].de<<" "<<people[i][j].cai;
		}
	}
}

1019 数字黑洞 (20 分)

给定任一个各位数字不完全相同的 4 位正整数,如果我们先把 4 个数字按非递增排序,再按非递减排序,然后用第 1 个数字减第 2 个数字,将得到一个新的数字。一直重复这样做,我们很快会停在有“数字黑洞”之称的 6174,这个神奇的数字也叫 Kaprekar 常数。
例如,我们从6767开始,将得到

7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174
7641 - 1467 = 6174
… …

现给定任意 4 位正整数,请编写程序演示到达黑洞的过程。

输入格式:
输入给出一个 (0,104) 区间内的正整数 N。

输出格式:
如果 N 的 4 位数字全相等,则在一行内输出 N - N = 0000;否则将计算的每一步在一行内输出,直到 6174 作为差出现,输出格式见样例。注意每个数字按 4 位数格式输出。

输入样例 1:

6767
*结尾无空行

输出样例 1:

7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174
*结尾无空行

输入样例 2:

2222
*结尾无空行

输出样例 2:

2222 - 2222 = 0000
*结尾无空行

本人代码

#include <iostream>
#include <algorithm>
using namespace std;
void toArray(int N,int num[]){
	num[0] = N/1000;
	num[1] = N%1000/100;
	num[2] = N%100/10;
	num[3] = N%10;
}
int toNum(int num[]){return (num[0]*1000+num[1]*100+num[2]*10+num[3]);}
bool cmp(int a,int b){return a>b;}
int main() {
	int N,num[4],up,down;
	cin>>N;
	toArray(N,num);
	if(N%1111==0){
		printf("%d - %d = 0000",N,N);
	}else{
		do{
			sort(num,num+4);
			up = toNum(num);
			sort(num,num+4,cmp);
			down = toNum(num);
			N = down - up;
			printf("%04d - %04d = %04d",down,up,N);
			toArray(N,num);
			if(N != 6174) cout<<endl;
		}while( N != 6174 );
	}
	return 0;
}

柳神代码

#include <iostream>
#include <algorithm>
using namespace std;
bool cmp(char a, char b) {return a > b;}
int main() {
    string s;
    cin >> s;
    s.insert(0, 4 - s.length(), '0');
    do {
        string a = s, b = s;
        sort(a.begin(), a.end(), cmp);
        sort(b.begin(), b.end());
        int result = stoi(a) - stoi(b);
        s = to_string(result);
        s.insert(0, 4 - s.length(), '0');
        cout << a << " - " << b << " = " << s << endl;
    } while (s != "6174" && s != "0000");
    return 0;
}

学习知识点

1)整型(int、long long····)和string间的相互转换
数字转字符串:to_string(int);
字符串转数字:stio(string);

格式化数字字符串
格式长度不够补零:s.insert(0, 4 - s.length(), ‘0’);

总结

代码撰写优中有优,只要不是太烂的代码,第一时间内想出来的不复杂的、熟练的代码就是好代码

1024 科学计数法 (20 分)

科学计数法是科学家用来表示很大或很小的数字的一种方便的方法,其满足正则表达式 [±][1-9].[0-9]+E[±][0-9]+,即数字的整数部分只有 1 位,小数部分至少有 1 位,该数字及其指数部分的正负号即使对正数也必定明确给出。
现以科学计数法的格式给出实数 A,请编写程序按普通数字表示法输出 A,并保证所有有效位都被保留。

输入格式:
每个输入包含 1 个测试用例,即一个以科学计数法表示的实数 A。该数字的存储长度不超过 9999 字节,且其指数的绝对值不超过 9999。
输出格式:
对每个测试用例,在一行中按普通数字表示法输出 A,并保证所有有效位都被保留,包括末尾的 0。

输入样例 1:

+1.23400E-03
结尾无空行

输出样例 1:

0.00123400
结尾无空行

输入样例 2:

-1.2E+10
结尾无空行

输出样例 2:

-12000000000

代码

#include <iostream>
using namespace std;
int main() {
	string data;
	cin>>data;
	int i=0;
	while(data[i]!='E')
		i++;
	string d = data.substr(1,i-1);
	int z = stoi(data.substr(i+1));
	if(data[0] == '-') cout<<"-";
	if(z<0){
		cout<<"0.";
		for(int i=0;i<abs(z)-1;i++) cout<<"0";
		for(int i=0;i<d.length();i++)
			if (d[i] != '.') cout << d[i];
	}else{
		cout<<d[0];
		for(int i=2;i<z+2 && i<d.length();i++)
			cout<<d[i];
		if(z+2>=d.length()){
			for(int i=0;i<z+2-d.length();i++)
				cout<<"0";
		}else{
			cout<<".";
			for(int i=z+2;i<d.length();i++){
				cout<<d[i];
			}
		}
	}
	return 0;
}

知识点学习

字符串的分割:substr(start,end);
其中start和end都是string的下标,并且分割得到的字符串包含string[end]即:string[start]~string[end];

1025 反转链表 (25 分)

给定一个常数 K 以及一个单链表 L,请编写程序将 L 中每 K 个结点反转。例如:给定 L 为 1→2→3→4→5→6,K 为 3,则输出应该为 3→2→1→6→5→4;如果 K 为 4,则输出应该为 4→3→2→1→5→6,即最后不到 K 个元素不反转。

输入格式:
每个输入包含 1 个测试用例。每个测试用例第 1 行给出第 1 个结点的地址、结点总个数正整数 N (≤105)、以及正整数 K (≤N),即要求反转的子链结点的个数。结点的地址是 5 位非负整数,NULL 地址用 −1 表示。
接下来有 N 行,每行格式为:

Address Data Next

其中 Address 是结点地址,Data 是该结点保存的整数数据,Next 是下一结点的地址。

输出格式:
对每个测试用例,顺序输出反转后的链表,其上每个结点占一行,格式与输入相同。

输入样例:

00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
结尾无空行

输出样例:

00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1

代码

#include <iostream>
#include <algorithm>
using namespace std;
int main() {
	int first,length,change,temp;
	cin>>first>>length>>change;
	int data[100005],next[100005],list[100005];
	for(int i=0;i<length;i++){
		cin>>temp;
		cin>>data[temp]>>next[temp];
	}
	temp = first;
	length = 0;
	while(temp!=-1){
		list[length++] = temp;
		temp = next[temp];
	}
	for(int i=0;i<length - length%change;i+=change)
		reverse(begin(list)+i,begin(list)+i+change);
	for(int i=0;i<length-1;i++)
		printf("%05d %d %05d\n",list[i],data[list[i]],list[i+1]);
	printf("%05d %d -1",list[length-1],data[list[length-1]]);
	return 0;
}

总结

类似链表的逆转,关系到指向下一节点的地址,相对来说较复杂,通过建立一个数值数组data和一个对应下一节点的数组next,两数组的下标都为当前节点的地址,值则为当前节点的值以及当前节点的下一节点地址。在通过节点的链式关系,把整个表按顺序链接起来将地址依次存在新数组list内,即数组地址按顺序排列好,再将其地址进行逆转等处理,最终相应地址又可在data中取得数值,而顺序即是list中地址的顺序。

1035 插入与归并 (25 分)

根据维基百科的定义:

插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。
归并排序进行如下迭代操作:首先将原始序列看成 N 个只包含 1 个元素的有序子序列,然后每次迭代归并两个相邻的有序子序列,直到最后只剩下 1 个有序的序列。
现给定原始序列和由某排序算法产生的中间序列,请你判断该算法究竟是哪种排序算法?

输入格式:
输入在第一行给出正整数 N (≤100);随后一行给出原始序列的 N 个整数;最后一行给出由某排序算法产生的中间序列。这里假设排序的目标序列是升序。数字间以空格分隔。

输出格式:
首先在第 1 行中输出Insertion Sort表示插入排序、或Merge Sort表示归并排序;然后在第 2 行中输出用该排序算法再迭代一轮的结果序列。题目保证每组测试的结果是唯一的。数字间以空格分隔,且行首尾不得有多余空格。

输入样例 1:

10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0
结尾无空行

输出样例 1:

Insertion Sort
1 2 3 5 7 8 9 4 6 0
结尾无空行

输入样例 2:

10
3 1 2 8 7 5 9 4 0 6
1 3 2 8 5 7 4 9 0 6
结尾无空行

输出样例 2:

Merge Sort
1 2 3 8 4 5 7 9 0 6

本人代码

#include <iostream>
#include <algorithm>
using namespace std;
int main() {
	int n,l,type = 1,i,j;
	cin>>n;
	int a[n],b[n];
	for(int i=0;i<n;i++)
		cin>>a[i];
	for(int i=0;i<n;i++)
		cin>>b[i];
	for (i = 1; i < n && b[i-1] <= b[i]; i++);
    for (j = i; a[j] == b[j] && j < n; j++);
	printf("%s\n",j==n?"Insertion Sort":"Merge Sort");
	if(j==n){
		sort(b,b+i+1);
	}else{
		int d=2;
		for(i = 2;i<n;i*=2){
			int is = 1;
			for(j=0;j<n;j+=i){
				for(int x=j;x<j+i-1 && x<n;x++){
					if(b[x]>b[x+1]){
						is = 0;
						break;
					}
				}
				if(is==0) break;
			}
			if(is==1){
				d = i;
				break;
			}
		}
		for(i=0;i+d+d<=n;i+=(d+d))
			sort(b+i,b+i+d+d);
		sort(b+i,b+n);
	}
	for(int i=0;i<n;i++){
		if(i!=0)cout<<" ";
			cout<<b[i];
	}
	return 0;
}

柳神代码

#include <iostream>
#include <algorithm>
using namespace std;
int main() {
    int n, a[100], b[100], i, j;
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> a[i];
    for (int i = 0; i < n; i++)
        cin >> b[i];
    for (i = 0; i < n - 1 && b[i] <= b[i + 1]; i++);
    for (j = i + 1; a[j] == b[j] && j < n; j++);
    if (j == n) {
        cout << "Insertion Sort" << endl;
        sort(a, a + i + 2);
    } else {
        cout << "Merge Sort" << endl;
        int k = 1, flag = 1;
        while(flag) {
            flag = 0;
            for (i = 0; i < n; i++) {
                if (a[i] != b[i])
                    flag = 1;
            }
            k = k * 2;
            for (i = 0; i < n / k; i++)
                sort(a + i * k, a + (i + 1) * k);
            sort(a + n / k * k, a + n);
        }
    }
    for (j = 0; j < n; j++) {
        if (j != 0) printf(" ");
        printf("%d", a[j]);
    }
    return 0;
}

总结

这道题自己走了一条不正确的路(直接通过结果来判断排序的方法其实是不确定的)。判断序列是某种序列时,应该用初始序列依次进行相应排序方法,判断两序列是否相同来判断。

1050 螺旋矩阵 (25 分)

本题要求将给定的 N 个正整数按非递增的顺序,填入“螺旋矩阵”。所谓“螺旋矩阵”,是指从左上角第 1 个格子开始,按顺时针螺旋方向填充。要求矩阵的规模为 m 行 n 列,满足条件:m×n 等于 N;m≥n;且 m−n 取所有可能值中的最小值。
输入格式:
输入在第 1 行中给出一个正整数 N,第 2 行给出 N 个待填充的正整数。所有数字不超过 104,相邻数字以空格分隔。

输出格式:
输出螺旋矩阵。每行 n 个数字,共 m 行。相邻数字以 1 个空格分隔,行末不得有多余空格。

输入样例:

12
37 76 20 98 76 42 53 95 60 81 58 93
结尾无空行

输出样例:

98 95 93
42 37 81
53 20 76
58 60 76
结尾无空行

代码

#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;

bool cmp(int a,int b){
	return a>b;
}
int main() {
	int n,c,r,t=0;
	cin>>n;
	vector<int> a(n);
	for(c = sqrt(n);c>0;c--){
		if(n%c==0){
			r = n/c;
			break;
		}
	}
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	sort(a.begin(),a.end(),cmp);
	vector<vector<int> > v(r, vector<int>(c));
	for(int i=0;i<(c+1)/2;i++){
		for(int j=i;j<c-i && t<n;j++)
			v[i][j] = a[t++];
		for(int j = i+1;j<r-i-1 && t<n;j++)
			v[j][c-i-1] = a[t++];
		for(int j=c-i-1;j>=i && t<n;j--)
			v[r-i-1][j] = a[t++];
		for(int j=r-i-2;j>=i+1 && t<n;j--){
			v[j][i] = a[t++];
		}
	}
	for(int i=0;i<r;i++){
		for(int j=0;j<c;j++){
			if(j!=0)cout<<" ";
			cout<<v[i][j];
		}
		cout<<endl;
	}
	return 0;
}

总结

1)本题本来思路是对的,但是在循环的时候对于变量的梳理,逻辑不能在代码中清晰的表现,以为自己的思路是错的,最后直接去看了答案
对于这种逻辑绕弯多的代码,应该提高每个变量的性质的记忆性,不应该单纯的是a,b,r,c这类,可以是length,grade等赋予意思的变量,逻辑思维能力要提高,不要不坚定自己的思路。

2)在定义vecotr的时候应该给定空间(vector v(n))后才能直接用cin>>a[i],如果未赋值空间大小时应该用a.push_back(x);的方式添加元素

1052 卖个萌 (20 分)

萌萌哒表情符号通常由“手”、“眼”、“口”三个主要部分组成。简单起见,我们假设一个表情符号是按下列格式输出的:

[左手]([左眼][口][右眼])[右手]

现给出可选用的符号集合,请你按用户的要求输出表情。

输入格式:
输入首先在前三行顺序对应给出手、眼、口的可选符号集。每个符号括在一对方括号 []内。题目保证每个集合都至少有一个符号,并不超过 10 个符号;每个符号包含 1 到 4 个非空字符。
之后一行给出一个正整数 K,为用户请求的个数。随后 K 行,每行给出一个用户的符号选择,顺序为左手、左眼、口、右眼、右手——这里只给出符号在相应集合中的序号(从 1 开始),数字间以空格分隔。

输出格式:
对每个用户请求,在一行中输出生成的表情。若用户选择的序号不存在,则输出 Are you kidding me? @\/@。

输入样例:

[╮][╭][o][][/] [<][>]
[╯][╰][^][-][=][>][<][@][⊙]
[Д][▽][_][ε][^] …
4
1 1 2 2 2
6 8 1 5 5
3 3 4 3 3
2 10 3 9 3
结尾无空行

输出样例:

╮(╯▽╰)╭
<(@Д=)/~
o(ε)o
Are you kidding me? @/@
结尾无空行

代码

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
	vector<string> emoj[3];
	for(int i=0;i<3;i++){
		string temp;
		int left,len;
		getline(cin,temp);
		for(int j=0;j<temp.length();j++){
			if(temp[j]=='['){
				len = 0;
				left = ++j;
				while(j<temp.length()){
					if(temp[j]==']'){
						string s = temp.substr(left,len);
						emoj[i].push_back(s);
						break;
					}
					len++;j++;
				}
			}
		}
	}
	int a,b,c,d,e;
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a>>b>>c>>d>>e;
		if(a<1||b<1||c<1||d<1||e<1||a>emoj[0].size()||b>emoj[1].size()||
			c>emoj[2].size()||d>emoj[1].size()||e>emoj[0].size()){
			cout<<"Are you kidding me? @\\/@"<<endl;
			continue;
		}
		cout<<emoj[0][a-1]<<"("<<emoj[1][b-1]<<emoj[2][c-1]<<emoj[1][d-1]<<")"
			<<emoj[0][e-1]<<endl;
	}
	return 0;
}

总结

1)类似于这种类型的字符串分割应该要耐心,不要想着一定有更简洁的方法,有时候就是需要一个一个遍历然后获取开始结束的位置然后substr。(其实并不慢,只是自己觉得麻烦)
2)转义字符在输出时可能导致输出错误(需要输出则写两个就表示输出:%%表示输出% \\表示输出\)
3)对于乘积结果的类型判断:当要进行精确位数时,应该判断负数精确位数是受否进位变成0之后输出类型改变

1054 求平均值 (20 分)

本题的基本要求非常简单:给定 N 个实数,计算它们的平均值。但复杂的是有些输入数据可能是非法的。一个“合法”的输入是 [−1000,1000] 区间内的实数,并且最多精确到小数点后 2 位。当你计算平均值的时候,不能把那些非法的数据算在内。

输入格式:
输入第一行给出正整数 N(≤100)。随后一行给出 N 个实数,数字间以一个空格分隔。

输出格式:
对每个非法输入,在一行中输出 ERROR: X is not a legal number,其中 X 是输入。最后在一行中输出结果:The average of K numbers is Y,其中 K 是合法输入的个数,Y 是它们的平均值,精确到小数点后 2 位。如果平均值无法计算,则用 Undefined 替换 Y。如果 K 为 1,则输出 The average of 1 number is Y。

输入样例 1:

7
5 -3.2 aaa 9999 2.3.4 7.123 2.35
结尾无空行

输出样例 1:

ERROR: aaa is not a legal number
ERROR: 9999 is not a legal number
ERROR: 2.3.4 is not a legal number
ERROR: 7.123 is not a legal number
The average of 3 numbers is 1.38
结尾无空行

输入样例 2:

2
aaa -9999
结尾无空行

输出样例 2:

ERROR: aaa is not a legal number
ERROR: -9999 is not a legal number
The average of 0 numbers is Undefined
结尾无空行

本人代码

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
	int n,num=0;
	cin>>n;
	double sum;
	string temp;
	for(int j=0;j<n;j++){
		bool digit = true;
		cin>>temp;
		int pot=0;
		int i=0;
		if(temp[i]=='-')i++;
		if((temp[i]=='.' && temp.length()>=2)){
			digit = false;
		}else{
			for(i;i<temp.length();i++){
				if((temp[i]<'0' || temp[0]>'9') && temp[i] != '.'){
					digit = false;
					break;
				}
				if(temp[i]=='.'){
					pot++;
					if(pot>1 || temp.length()-i-1>2){
						digit = false;
						break;
					}
				}
			}
		}
		if(digit){
			double data = stof(temp);
			if(data<=1000 && data>=-1000){
				sum += data;num++;
			}else{
				cout<<"ERROR: "<<temp<<" is not a legal number"<<endl;
			}
			
		}else
			cout<<"ERROR: "<<temp<<" is not a legal number"<<endl;
	}
	if(num == 1)
        printf("The average of 1 number is %.2f", sum);
    else if(num > 1)
        printf("The average of %d numbers is %.2f", num, sum / num);
    else
        printf("The average of 0 numbers is Undefined");
	return 0;
}

柳神代码

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
int main() {
    int n, cnt = 0;
    char a[50], b[50];
    double temp = 0.0, sum = 0.0;
    cin >> n;
    for(int i = 0; i < n; i++) {
        scanf("%s", a);
        sscanf(a, "%lf", &temp);
        sprintf(b, "%.2f",temp);
        int flag = 0;
        for(int j = 0; j < strlen(a); j++)
            if(a[j] != b[j]) flag = 1;
        if(flag || temp < -1000 || temp > 1000) {
            printf("ERROR: %s is not a legal number\n", a);
            continue;
        } else {
            sum += temp;
            cnt++;
        }
    }
    if(cnt == 1)
        printf("The average of 1 number is %.2f", sum);
    else if(cnt > 1)
        printf("The average of %d numbers is %.2f", cnt, sum / cnt);
    else
        printf("The average of 0 numbers is Undefined");
    return 0;
}

总结

1)输入重新赋值:
sscanf(赋值变量字符串,“变量类型”,被赋值变量); sprintf(被赋值变量字符串,“变量类型”,赋值变量) //以此可以判断输入的格式是否与想要的格式相同
sscanf() – 从一个字符串中读进与指定格式相符的数据
sprintf() – 字符串格式化命令,主要功能是把格式化的数据写入某个字符串中
scanf("%s", a);
sscanf(a, “%lf”, &temp);
sprintf(b, “%.2f”,temp);
2)字符串转数字:转整数:stoi() 转double:stod() 转long long:stol() 转float:stof()

易错点
213213.也算合法,当只有一个数据时numbers变为number单数

1054 集体照 (25 分)

拍集体照时队形很重要,这里对给定的 N 个人 K 排的队形设计排队规则如下:
每排人数为 N/K(向下取整),多出来的人全部站在最后一排;
后排所有人的个子都不比前排任何人矮;
每排中最高者站中间(中间位置为 m/2+1,其中 m 为该排人数,除法向下取整);
每排其他人以中间人为轴,按身高非增序,先右后左交替入队站在中间人的两侧(例如5人身高190、188、186、175、170,则队形为175、188、190、186、170。这里假设你面对拍照者,所以你的左边是中间人的右边);
若多人身高相同,则按名字的字典序升序排列。这里保证无重名。
现给定一组拍照人,请编写程序输出他们的队形。
输入格式:

每个输入包含 1 个测试用例。每个测试用例第 1 行给出两个正整数 N(≤104,总人数)和 K(≤10,总排数)。随后 N 行,每行给出一个人的名字(不包含空格、长度不超过 8 个英文字母)和身高([30, 300] 区间内的整数)。

输出格式:

输出拍照的队形。即K排人名,其间以空格分隔,行末不得有多余空格。注意:假设你面对拍照者,后排的人输出在上方,前排输出在下方。

输入样例:

10 3
Tom 188
Mike 170
Eva 168
Tim 160
Joe 190
Ann 168
Bob 175
Nick 186
Amy 160
John 159
结尾无空行

输出样例:

Bob Tom Joe Nick
Ann Mike Eva
Tim Amy John
结尾无空行

本人代码

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

typedef struct People{
	string name;
	int height;
}person;

bool cmp(person p1,person p2){
	if(p1.height!=p2.height){
		return p1.height<p2.height;
	}else{
		return p1.name>p2.name;
	}
}

int main(){
	int n,k;
	vector <person> people;
	cin>>n>>k;
	person p;
	for(int i=0;i<n;i++){
		cin>>p.name>>p.height;
		people.push_back(p);
	}
	sort(people.begin(),people.end(),cmp);
	if(n<k)
		k = n;
	int length = n/k;
	int be,length1 = length;
	for(int i=k-1;i>=0;i--){
		if(i==k-1)length1 += n%k;
		else length1 = length;
		if(length1==1){
			cout<<people[i].name;
		}else{
			if(length1%2==0)be = 0;
			else be = 1;
			int j;
			for(j=i*length+be;(j-(i*length+be))<length1-1;j+=2)
				cout<<people[j].name<<" ";
			j--;
			cout<<people[j].name;
			for( j-=2;j>=i*length;j-=2)
				cout<<" "<<people[j].name;
			}
		if(i!=0)cout<<endl;
	}
	return 0;
}

柳神代码

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct node {
    string name;
    int height;
};
int cmp(struct node a, struct node b) {
    return a.height != b.height ? a.height > b.height : a.name < b.name;
}
int main() {
    int n, k, m;
    cin >> n >> k;
    vector<node> stu(n);
    for(int i = 0; i < n; i++) {
        cin >> stu[i].name >> stu[i].height;
    }
    sort(stu.begin(), stu.end(), cmp);
    int t = 0, row = k;
    while(row) {
        if(row == k)
            m = n - n / k * (k - 1);
        else
            m = n / k;
        vector<string> ans(m);
        ans[m / 2] = stu[t].name;
        // 左边一列
        int j = m / 2 - 1;
        for(int i = t + 1; i < t + m; i = i + 2)
            ans[j--] = stu[i].name;
        // 右边一列
        j = m / 2 + 1;
        for(int i = t + 2; i < t + m; i = i + 2)
            ans[j++] = stu[i].name;
        // 输出当前排
        cout << ans[0];
        for(int i = 1; i < m; i++)
            cout << " " << ans[i];
        cout << endl;
        t = t + m;
        row--;
    }
    return 0;
}

总结

对于多层逻辑的代码觉得太麻烦,同时自己在做题的时候又不够冷静,没能细心的一步一步分析,理清思路,对于临界条件判断不够准确,所以代码很容易出错。

1068 万绿丛中一点红 (20 分)

对于计算机而言,颜色不过是像素点对应的一个 24 位的数值。现给定一幅分辨率为 M×N 的画,要求你找出万绿丛中的一点红,即有独一无二颜色的那个像素点,并且该点的颜色与其周围 8 个相邻像素的颜色差充分大。
输入格式:
输入第一行给出三个正整数,分别是 M 和 N(≤ 1000),即图像的分辨率;以及 TOL,是所求像素点与相邻点的颜色差阈值,色差超过 TOL 的点才被考虑。随后 N 行,每行给出 M 个像素的颜色值,范围在 [0,224) 内。所有同行数字间用空格或 TAB 分开。

输出格式:
在一行中按照 (x, y): color 的格式输出所求像素点的位置以及颜色值,其中位置 x 和 y 分别是该像素在图像矩阵中的列、行编号(从 1 开始编号)。如果这样的点不唯一,则输出 Not Unique;如果这样的点不存在,则输出 Not Exist。

输入样例 1:

8 6 200
0 0 0 0 0 0 0 0
65280 65280 65280 16711479 65280 65280 65280 65280
16711479 65280 65280 65280 16711680 65280 65280 65280
65280 65280 65280 65280 65280 65280 165280 165280
65280 65280 16777015 65280 65280 165280 65480 165280
16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215
结尾无空行

输出样例 1:

(5, 3): 16711680
结尾无空行

输入样例 2:

4 5 2
0 0 0 0
0 0 3 0
0 0 0 0
0 5 0 0
0 0 0 0
结尾无空行

输出样例 2:

Not Unique
结尾无空行

输入样例 3:

3 3 5
1 2 3
3 4 5
5 6 7
结尾无空行

输出样例 3:

Not Exist
结尾无空行

本人代码

#include<iostream>
#include<cmath>
#include<map>
using namespace std;
int xs[1001][1001]={0};
int n,m,tol;//m是列数,n是行数
bool judge(int i,int j)//i指向行,j指向列
{
    if(i-1>=0&&i-1<n&&j-1>=0&&j-1<m)
    {
        if(abs(xs[i][j]-xs[i-1][j-1])<=tol)return false;
    }
    if(i-1>=0&&i-1<n)
    {
        if(abs(xs[i][j]-xs[i-1][j])<=tol)return false;
    }
    if(i-1>=0&&i-1<n&&j+1>=0&&j+1<m)
    {
        if(abs(xs[i][j]-xs[i-1][j+1])<=tol)return false;
    }
    if(j-1>=0&&j-1<m)
    {
        if(abs(xs[i][j]-xs[i][j-1])<=tol)return false;
    }
    if(j+1>=0&&j+1<m)
    {
        if(abs(xs[i][j]-xs[i][j+1])<=tol)return false;
    }
    if(i+1>=0&&i+1<n&&j-1>=0&&j-1<m)
    {
        if(abs(xs[i][j]-xs[i+1][j-1])<=tol)return false;
    }
    if(i+1>=0&&i+1<n)
    {
        if(abs(xs[i][j]-xs[i+1][j])<=tol)return false;
    }
    if(i+1>=0&&i+1<n&&j+1>=0&&j+1<m)
    {
        if(abs(xs[i][j]-xs[i+1][j+1])<=tol)return false;
    }
    return true;
}
int main()
{
    int cnt=0,x=0,y=0;
    map<int,int> appear;//记录出现次数
    cin>>m>>n>>tol;//m是列数,n是行数
    for(int i=0;i<n;i++)for(int j=0;j<m;j++)//读入像素
    {
        scanf("%d",&xs[i][j]);
        appear[xs[i][j]]++;
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(appear[xs[i][j]]==1&&judge(i,j))
            {
                cnt++;
                x=j+1;
                y=i+1;
            }
        }
    }
    if(cnt==1)printf("(%d, %d): %d\n",x,y,xs[y-1][x-1]);
    else if(cnt==0)cout<<"Not Exist"<<endl;
    else cout<<"Not Unique"<<endl;
    return 0;
}

柳神代码

#include <iostream>
#include <vector>
#include <map>
using namespace std;
int m, n, tol;
vector<vector<int>> v;
int dir[8][2] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}};
bool judge(int i, int j) {
    for (int k = 0; k < 8; k++) {
        int tx = i + dir[k][0];
        int ty = j + dir[k][1];
        if (tx >= 0 && tx < n && ty >= 0 && ty < m && v[i][j] - v[tx][ty] >= 0 - tol && v[i][j] - v[tx][ty] <= tol) return false;
    }
    return true;
}
int main() {
    int cnt = 0, x = 0, y = 0;
    scanf("%d%d%d", &m, &n, &tol);
    v.resize(n, vector<int>(m));
    map<int, int> mapp;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            scanf("%d", &v[i][j]);
            mapp[v[i][j]]++;
        }
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (mapp[v[i][j]] == 1 && judge(i, j) == true) {
                cnt++;
                x = i + 1;
                y = j + 1;
            }
        }
    }
    if (cnt == 1)
        printf("(%d, %d): %d", y, x, v[x-1][y-1]);
    else if (cnt == 0)
        printf("Not Exist");
    else
        printf("Not Unique");
    return 0;
}

柳神代码总结

首先这个点必须是唯一的,所以用map标记如果不是唯一的点就不用考虑了~接着对于每个点,判断它的周围八个点与它的差值是否大于阈值,如果有一个点没有满足大于阈值就return false~最后记得输入的时候是列、行——m、n,输出的时候也是列、行坐标~

1073 多选题常见计分法 (20 分)

批改多选题是比较麻烦的事情,有很多不同的计分方法。有一种最常见的计分方法是:如果考生选择了部分正确选项,并且没有选择任何错误选项,则得到 50% 分数;如果考生选择了任何一个错误的选项,则不能得分。本题就请你写个程序帮助老师批改多选题,并且指出哪道题的哪个选项错的人最多。
输入格式:
输入在第一行给出两个正整数 N(≤1000)和 M(≤100),分别是学生人数和多选题的个数。随后 M 行,每行顺次给出一道题的满分值(不超过 5 的正整数)、选项个数(不少于 2 且不超过 5 的正整数)、正确选项个数(不超过选项个数的正整数)、所有正确选项。注意每题的选项从小写英文字母 a 开始顺次排列。各项间以 1 个空格分隔。最后 N 行,每行给出一个学生的答题情况,其每题答案格式为 (选中的选项个数 选项1 ……),按题目顺序给出。注意:题目保证学生的答题情况是合法的,即不存在选中的选项数超过实际选项数的情况。

输出格式:
按照输入的顺序给出每个学生的得分,每个分数占一行,输出小数点后 1 位。最后输出错得最多的题目选项的信息,格式为:错误次数 题目编号(题目按照输入的顺序从1开始编号)-选项号。如果有并列,则每行一个选项,按题目编号递增顺序输出;再并列则按选项号递增顺序输出。行首尾不得有多余空格。如果所有题目都没有人错,则在最后一行输出 Too simple。

输入样例 1:

3 4
3 4 2 a c
2 5 1 b
5 3 2 b c
1 5 4 a b d e
(2 a c) (3 b d e) (2 a c) (3 a b e)
(2 a c) (1 b) (2 a b) (4 a b d e)
(2 b d) (1 e) (1 c) (4 a b c d)
结尾无空行

输出样例 1:

3.5
6.0
2.5
2 2-e
2 3-a
2 3-b
结尾无空行

输入样例 2:

2 2
3 4 2 a c
2 5 1 b
(2 a c) (1 b)
(2 a c) (1 b)
结尾无空行

输出样例 2:

5.0
5.0
Too simple
结尾无空行

代码

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
int main() {
    int n, m, optnum, truenum, temp, maxcnt = 0;
    int hash[] = {1, 2, 4, 8, 16}, opt[1010][110] = {0};
    char c;
    scanf("%d %d", &n, &m);
    vector<int> fullscore(m), trueopt(m);
    vector<vector<int>> cnt(m, vector<int>(5));
    for (int i = 0; i < m; i++) {
        scanf("%d %d %d", &fullscore[i], &optnum, &truenum);
        for (int j = 0; j < truenum; j++) {
            scanf(" %c", &c);
            trueopt[i] += hash[c-'a'];
        }
    }
    for (int i = 0; i < n; i++) {
        double grade = 0;
        for (int j = 0; j < m; j++) {
            getchar();
            scanf("(%d", &temp);
            for (int k = 0; k < temp; k++) {
                scanf(" %c)", &c);
                opt[i][j] += hash[c-'a'];
            }
            int el = opt[i][j] ^ trueopt[j];
            if (el) {
                if ((opt[i][j] | trueopt[j]) == trueopt[j]) {
                    grade += fullscore[j] * 1.0 / 2;
                }
                if (el) {
                    for (int k = 0; k < 5; k++)
                        if (el & hash[k]) cnt[j][k]++;
                }
            } else {
                grade += fullscore[j];
            }
        }
        printf("%.1f\n", grade);
    }
    for (int i = 0; i < m; i++)
        for (int j = 0; j < 5; j++)
            maxcnt = maxcnt > cnt[i][j] ? maxcnt : cnt[i][j];
    
    if (maxcnt == 0) {
        printf("Too simple\n");
    } else {
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < cnt[i].size(); j++) {
                if (maxcnt == cnt[i][j])
                    printf("%d %d-%c\n", maxcnt, i+1, 'a'+j);
            }
        }
    }
    return 0;
}

1089 狼人杀-简单版 (20 分)

以下文字摘自《灵机一动·好玩的数学》:“狼人杀”游戏分为狼人、好人两大阵营。在一局“狼人杀”游戏中,1 号玩家说:“2 号是狼人”,2 号玩家说:“3 号是好人”,3 号玩家说:“4 号是狼人”,4 号玩家说:“5 号是好人”,5 号玩家说:“4 号是好人”。已知这 5 名玩家中有 2 人扮演狼人角色,有 2 人说的不是实话,有狼人撒谎但并不是所有狼人都在撒谎。扮演狼人角色的是哪两号玩家?
本题是这个问题的升级版:已知 N 名玩家中有 2 人扮演狼人角色,有 2 人说的不是实话,有狼人撒谎但并不是所有狼人都在撒谎。要求你找出扮演狼人角色的是哪几号玩家?

输入格式:
输入在第一行中给出一个正整数 N(5≤N≤100)。随后 N 行,第 i 行给出第 i 号玩家说的话(1≤i≤N),即一个玩家编号,用正号表示好人,负号表示狼人。

输出格式:
如果有解,在一行中按递增顺序输出 2 个狼人的编号,其间以空格分隔,行首尾不得有多余空格。如果解不唯一,则输出最小序列解 —— 即对于两个序列 A=a[1],…,a[M] 和 B=b[1],…,b[M],若存在 0≤k<M 使得 a[i]=b[i] (i≤k),且 a[k+1]<b[k+1],则称序列 A 小于序列 B。若无解则输出 No Solution。

输入样例 1:

5
-2
+3
-4
+5
+4
结尾无空行

输出样例 1:

1 4
结尾无空行

输入样例 2:

6
+6
+3
+1
-5
-2
+4
结尾无空行

输出样例 2(解不唯一):

1 5
结尾无空行

输入样例 3:

5
-2
-3
-4
-5
-1
结尾无空行

输出样例 3:

No Solution
结尾无空行

代码

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

int main() {
    int n;
    cin>>n;
    vector<int> v(n+1);
    for(int i=1;i<=n;i++)
    	cin>>v[i];
    for(int i=1;i<=n;i++){
    	for(int j=i+1;j<=n;j++){
    		vector<int> lang(n+1,1),ans;
    		lang[i] = lang[j] = -1;
    		for(int k=1;k<=n;k++){
    			if(v[k]*lang[abs(v[k])]<0)ans.push_back(k);
			}
			if(ans.size()==2 && lang[ans[0]]+lang[ans[1]] == 0){
				cout<<i<<" "<<j;
				return 0;
			}
		}
	}
	cout<<"No Solution";
    return 0;
}

剩余
输入输出都可以用八进制%o,十进制%d,十六进制%x

超长数字转换进制类型(例如十六转八进制此类:二的方,其余类似转10进制不行),可以以字符串类型输入,然后全部转换成二进制,再将二进制转换成目标进制

十进制转其它进制:
1、短的
1)转八进制,十六进制:直接%o,%x
2)转其它:用/和%共同实现

2、长的
用/和%共同实现

其它进制转十进制:
1、短的:直接一位一位乘对应权值
2、长的

找回文数(12321)如果指明了位数,可以直接遍历查询符合条件的回文数

int最大十位:4,290,000,000
long long最大十九位:9,000,000,000,000,000,000

C几几随机事件实现:
void init() {
for(int i = 0 ; i <= n ; i ++)
c[i][0] = 1;
for(int i = 0 ; i <= n ; i ++)
c[i][i] = 1;
for(int i = 2 ; i <= n ; i ++) {
for(int j = 1 ; j < i ; j ++) {
c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
}
}
}
当数据过大时不能用公式,类似n*(n-1)(n-1)/(12*3),当数据过大时取模也没用,因为当遍历到分子除分母除不尽时就有问题了,而取模又不能让sum为double浮点数
ll C(int n,int m){
ll sum=1;
ll chu = 1;
for(int i=1;i<=m;i++){
sum *= n-i+1;
chu *=i;
sum %= Mod;
}
return sum;
}

求一维数组的最大子区间/符合条件的子区间:前缀和的方法,最后相减

求二维数组内符合条件的子区间:二维前缀法,例题:https://tigerisland.blog.csdn.net/article/details/119704146

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值