Point 1
如何将一维数组的所有元素初始化为0?
1.int a[5] = {0};
2.将数组a定义成全局变量或静态变量
3.memset(a,0,sizeof(a))
Point 2
下列描述中,正确的是()
1.int a[3][3] = {1};
定义了数组a,并对数组a赋初值。此时,a[0][0]的值为1,而其
余元素的值都为0。
2.int b[4][3] = {{ }, { }, { },{9}};
定义了数组b,并对数组赋初值。此时,b[3][0]的值为9,而
其余元素的值都为0。
3.int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int a[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
以上2种数组初始化方法是等价的。
int b[4][3] = {{1, 2, 3}, { }, {4, 5}};
4.int b[4][3] = {1, 2, 3, 0, 0, 0, 4, 5};
以上2句是等价的
Point 3
以下字符数组的定义和初始化正确的是
1.char str[ ]="Hello";
2.char str[ ] = {‘H', ‘e', ‘l', ‘l', ‘o', '\0'};
3.char str[ ] = {“Hello"};
4.char str[6] = {‘H', ‘e', ‘l', ‘l', ‘o'};
Point 4
hypot函数头文件math.h或cmath
hypot(a,b)的返回值为double类型
Point 5
Point 6
Point 7
Point 8
Point 9
Point 10
Point 11
Point 12
Point 13
Point 14
Point 15
Point 16
NO.1
题目描述:
题意分析:本题需要通过题目给出的函数返回一个整数,但经过简单的计算可以发现它可能超过整形int的范围,于是返回类型应该设计为long long.
解题思路:题目给出的式子共分两种情况,第一种情况进行递归处理即可。第二种情况是 ∣r-l∣≤5.此时返回的是区间最大值。这里有一个细节是,在max函数里,因为M函数的返回值是long long,而max函数不能把两个不同类型的变量作比较,所以需要把常数7也改为long long类型的,即写作(long long) 7。
复杂度分析:O(n)
带注释的代码:
#include<iostream>
#include<cmath>//这里需要用到max和abs函数,因此要加这个头文件
using namespace std;
int n;
long long a[500005];//注意定义的是长整型
long long M(int l,int r){
if(abs(r-l)<=5){
int ans=0;
for(int i=l;i<=r;i=i+1){
if(a[i]>ans){
ans=a[i];
}//找到a[i]的最大值
}
return ans;
}
else{
return (M(l,(l+r)/2)%max(M((l+r)/2+1,r),(long long)7))+a[(l+r)/2]-1;//按照题目要求写,注意数字7要定义为long long
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i=i+1){
scanf("%lld",&a[i]);
}
printf("%lld\n",M(1,n));
return 0;
}
NO.2
题目描述:
题意分析: 参赛者需要猜测所给的谜底中的所有字母,每猜对一个字母,就算猜中谜底中对应的所有该字母,每猜错一次,刽子手就会在图纸上划一笔,累计画7笔,参赛者就输了,如果在画完之前猜出所有谜底,则参赛者获胜,如果参赛者在猜错7次前放弃,则参赛者退出。
解题思路: 用字符串数组保存三种结果输出;标记谜底中所有字符,统计谜底中字符的种类数,对照参赛者的猜测结果,如果猜到了一种,谜底中剩余未被猜出字符个数减一,猜错了,错误次数加一,全部猜对了,返回0,猜错次数累计7次,返回1,没有输赢,返回2.
复杂度分析:O(n)
带注释的代码:
#include<iostream>
using namespace std;
int check(string &a, string &b) {//a为答案,b为猜侧值
int t=0;//统计当前还有多少种字符没有被猜出
int w=0;//记录当前猜错次数
int num1[26]={0},num2[26]={0};//num[i]统计字符'a'+i是否出现过
for(int i=0;i<a.length();i=i+1){
num1[a[i]-'a']++;
}//统计字符种类,也可以num1[a[i]-'a']=1,反正就是标记一下
for(int i=0;i<26;i=i+1){
if(num1[i]){
t=t+1;
}
}//统计答案中字符种类
for(int i=0;i<b.length();i++) {//遍历b字符串中各个字符
if(num2[b[i]-'a']!=1) {//如果b中还没猜过该字符
if (num1[b[i]-'a']) {//如果a中该字符出现过,猜对一次,剩余未猜中字符数total减一,猜完返回0,str[0]=win
t=t-1;
if(t==0) return 0;
}
else if(num1[b[i]-'a']!=1) {//当前猜测的字符未在a中出现,说明猜错了,记录猜错次数,达到7次则猜数失败,返回1,str[1]=lose
w=w+1;
if(w>=7) return 1;
}
}
num2[b[i]-'a']= 1;//标记当前字符已经猜过了,避免重复统计
}
return 2;//猜完未错也未对,出局,str[2]=chicked out
}
int main()
{
int n;
string s1, s2;
string str[] = { "You win.","You lose.","You chickened out." };//三种情况
while (~scanf("%d", &n) && n != -1) {
printf("Round %d\n",n);
cin>>s1>>s2;
cout<<str[check(s1,s2)];//通过check()函数返回值作为下标直接输出对应游戏结果
printf("\n");
}
return 0;
}
NO.3
题目描述:
#include<iostream>
#include<vector>
using namespace std;
int main() {
int N,k,m;
while(~scanf("%d %d %d",&N,&k,&m)){
if(N==0&&k==0&&m==0){
break;
}
vector<int>a(N+1);//1~N;
int i=1,j=N;
int c1=0,c2=0;//分别记录i查找和j查找的有效次数
int ans=0;//记录当前已经挑选了几人
int same=0;//记录第一次找到的人的编号,因为两次查找可以找同一个人,但第一次找到的人因为被选中,已经被打上标记了,第二次查找中可能会跳过这个人,然而用same记录,标志这个人可以被选中
bool flag=0;//标记两次选人是否选择到同一个人身上
while(ans<N){
while(1){//约瑟夫环,间隔n(题目中为k),逆时针,也就是顺着编号
if(!a[i])c1++;
if(c1%k==0){
a[i]=1;same=i;c1=0;break;//一次有效间距查找完成后,c1清0;
}
i=i%N+1;//1~N;
}
while(1){//顺时针,间隔m,逆着编号
if(!a[j]||j==same){
c2=c2+1;
}//没有被挑选走或者与当前的i(same)是同一个数,都算一次有效查找
if(c2%m==0){
if(j==same){
flag=true;
}
else{
a[j]=1;
}
c2=0;//一次有效间距查找完成后,c2清0
break;
}
j=(j-1+N-1)%N+1;//1~N;
}
if(flag){
printf("%3d",same);
ans=ans+1;
flag=false;//flag状态清零
}
else{
printf("%3d%3d",i,j);
ans=ans+2;
}
same=0;//一次进行两种查找,完成后本轮查找的same已经被调用过了 ,需要重新更新以便下一轮查找使用
if(ans<N)printf(",");//后续还有人未被挑选,打印后缀','
else break;//ans>=N,所有人都被挑选完了,任务完成
while(a[i]){
i=i%N+1;
}//查找下一个未被挑选的i,作为下一次循环查找的出发点
while(a[j])j=(j-1+N-1)%N+1;//查找下一个未被挑选的j ,作为下一次查找的出发点
}
printf("\n");
}
return 0;
}
NO.4
题目描述:
题意分析:有 a 名同学与 n 首歌,给出每位同学从每首歌中获得的快乐值,按照给予的总快乐值即欢乐度从高到低排序,选出前 m 首,并特殊处理zyl最喜欢的歌(如果zyl最喜欢的歌已经在歌单中,把这首歌提到歌单的第一个位置,如果不在,把zyl最喜欢的曲目代替已经选择好的歌单里最后一首歌)求出最终歌单。
解题思路:先不考虑zyl,或者可以采用结构体排序,用一个结构体记录两个信息:欢乐度d和编号id,然后使用 sort,按欢乐度从大到小排序。然后记录她最喜欢歌的编号。在学号为 b 时,使用一个变量maxid记录快乐值最多的歌的编号。然后就是判断了。在排好序后,我们先在前m首歌中找一遍,看看有没有她最喜欢的歌。如果没有,就先输出前m−1首歌的编号,再输出maxid,这就达到了删去最后一首歌,并把她最喜欢的歌放在最后的效果。如果有,那就先输出maxid,然后依次输出前m首歌的编号,但碰到maxid时,就直接跳过。
复杂度分析:O(a+m)
带注释的代码:
#include<bits/stdc++.h>
using namespace std;
struct song{
int d,id;//d表示欢乐度,id表示编号
}f[100005];
bool cmp(song x,song y){
return x.d>y.d;//按照欢乐度从大到小排列
}
int maxd=-1,maxid=0;
int n,m,a,b;
int main(){
scanf("%d %d %d %d",&n,&m,&a,&b);
for(int i=1;i<=a;i++){
for(int j=1;j<=n;j++){
int x;
scanf("%d",&x);
if(i==b&&x>maxd){//maxd和maxid存zyl最喜欢的歌的欢乐度和编号
maxd=x;
maxid=j;
}
f[j].d+=x;f[j].id=j;
}
}
sort(f+1,f+1+n,cmp);//使用sort函数排序
int flag=0;
for(int i=1;i<=m;i=i+1){
if(f[i].id==maxid){//判断maxid是否在歌单里
flag=1;
}
}
if(flag==1){
printf("%d",maxid);//在歌单里,先输出maxid
for(int i=1;i<=m;i=i+1){
if(f[i].id!=maxid){
printf(" %d",f[i].id);//记得跳过maxid,因为之前已经输出了
}
}
}
else{
for(int i=1;i<m;i=i+1){
printf("%d ",f[i].id);//不在歌单里,先输出前m-1首
}
printf("%d",maxid);
}
}
NO.5
题目描述:
题意分析:输出每次操作后正在访问的网址。
解题思路:运用栈的思维,用两个栈来存,s1存前面的网址,s1的栈顶表示当前页面的网址,s2存后面的网址。
带注释的代码:
#include<iostream>
#include<cstring>
#include<sstream>
#include<stack>
#include<queue>
using namespace std;
int main(){
// BACK:访问上一个界面
// FORWORD:访问下一个界面
// VISIT:访问一个新页面
// QUIT:结束访问
stack<string> s1, s2;
s1.push("http://www.acm.org/");
string s, str;
//用两个栈来存,s1存前面的,s1的栈顶表示当前页面,s2存后面的
while(cin >> s && s != "QUIT"){
if(s == "VISIT"){
cin >> str;
s1.push(str);
//访问新页面,下一页要清空
while(s2.size()){
s2.pop();
}
cout << str << "\n";
}else if(s == "BACK"){
if(s1.size() == 1){
//如果s1的size为1就不能继续往前了
cout << "Ignored\n";
continue;
}
s2.push(s1.top());
s1.pop();
cout << s1.top() << "\n";
}else if(s == "FORWARD"){
if(s2.empty()){
//s2为空就不能下一页了
cout << "Ignored\n";
continue;
}
cout << s2.top() << "\n";
s1.push(s2.top());
s2.pop();
}
}
}
NO.6
题目描述:
题意分析:某部队进行新兵队列训练,将新兵按顺依次编号并头开始轮流进行一至二报数、一至三报数直到剩下的人 数不超过三人为止。从头开始一至二报数,应报到二的出列,剩下的按序重新排列
解题思路:采用vector模拟删数的过程
1 2 3 4 5 6 7 8
=>1 3 5 7
复杂度分析:O(n)
带注释的代码:
#include <iostream>
#include <vector>
using namespace std;
int main(){
int T;
cin >> T;
while (T--){
int n;
cin >> n;
vector<int> v;
for (int i = 1; i <= n; i++)
v.push_back(i); //输入数据
while (v.size() > 3){
int sum = v.size();
for (int i = 1; i <= sum / 2; i++)//报道2的出列 ,总共要删sum/2个
v.erase(v.begin() + i);//举例:i=1的时候 ,删去了vector里的2,然后vector里后面的数都往前1格 ,i=2的时候看似删的是3, 其实是4(因为4往前了一格 ,占了3的位置)
sum = v.size();
if (sum <= 3)
break;//模拟了第一轮报1~3的所有报到3的人
for (int i = 1; i <= sum / 3; i++){
v.erase(v.begin() + i * 2);
}//如果 此时剩的人数比3要多 ,在进行下一轮报数
}
for (int i = 0; i < v.size(); i++){
if (i == 0)
cout << v[i];
else
cout << ' ' << v[i];
}
cout << '\n ';
}
return 0;
}
NO.7
题目描述:
题意分析:给定一个数字k,保证前k个人为好人,后k个人为坏人,求解m为多少时约瑟夫环只会把坏人踢出去。
解题思路:我们可以发现k很小,最大只有13,因此我们考虑用暴力的方式解决问题。先采用约瑟夫环的递推公式求解每一个k对应的m,然后就用打表得解。
复杂度分析:O(n)
带注释的代码:
#include<iostream>
using namespace std;//运用公式(起+m-1)%(长度)暴力求解每一个m
int a[14]={0,2,7,5,30,169,441,1872,7632,1740,93313,459901,1358657,2504881};//打表法
int main(){
int k;
while(~scanf("%d",&k)){
if(k==0){
break;
}
printf("%d\n",a[k]);
}
}