4.1排序
A1012 The Best Rank
问题;这题数据太多了,非常繁杂,结构体都不知道该怎么建立了,一开始想着是建立八个变量加一个id, 但这样后面每个人自己打印最佳rank的时候就不好做,然后又想着写二维数组,但是排序又不好排。
书中的思路:1.结构体中直接定义grade[4], 同时为了后面输出方面,0-A,1-C,2-M,3-E,数字表示的是位序。然后定义全局变量now,这是为了在比较函数中可以使用这个变量 ,这样的话在循环now,0-4的时候,每次循环进行一次,stu[N]都会排列一次,因此每次排完序,都得保存对应的rank,书中定义了一个二维数组,rank [1000000] 4] (辣鸡编辑器,中括号的使用被占据了,打出来会自动屏蔽),关于rank的问题直接使用书中的通用的一个循环就可以完成了。结束完排序后,输入待查询的ID,若没有返回NA,有的话,就找出Rank [id] 0-3]中的最小值,一次冒泡就可以完成,最后直接打印输出。
以下为书中代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
struct Student {
int id;
int grade[4];
}stu[2010];
char course[4]={'A', 'C', 'M', 'E'};
int Rank[1000000][4]={0};
int now; //cmp函数中使用,表示当前按now号分数排序stu数组
bool cmp(Student a, Student b) {
return a.grade[now]>b.grade[now];
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
for(int i=0; i<n; i++) {
scanf("%d%d%d%d", &stu[i].id, &stu[i].grade[1], &stu[i].grade[2], &stu[i].grade[3]);
stu[i].grade[0]=round((stu[i].grade[1]+stu[i].grade[2]+stu[i].grade[3])/3.0);
}
for(now=0; now<4; now++) {
sort(stu, stu+n, cmp);
Rank[stu[0].id][now]=1;
for(int i=1; i<n; i++) {
if(stu[i].grade[now]==stu[i-1].grade[now]){
Rank[stu[i].id][now]=Rank[stu[i-1].id][now];
} else {
Rank[stu[i].id][now]=i+1;
}
}
}
int query;
for(int i=0; i<m; i++) {
scanf("%d", &query);
if(Rank[query][0]==0) {
printf("N/A\n");
} else {
int k=0;
for(int j=0; j<4; j++) {
if(Rank[query][j]<Rank[query][k]) {
k=j;
}
}
printf("%d %c\n", Rank[query][k], course[k]);
}
}
return 0;
}
A1016 Phone Bills
问题:1.由于题目是用英语写的,有些单词不认识导致无法完整理解题意,还是要努力背单词啊!这种问题其实不应该出现的。
2.这道题复杂的地方在于首先读入的数据很多,其次需要进行很多繁琐的步骤使得读入的数据可以使用。
3.这种要求特别的题目一定要理清思路,结构体如何构建,是否需要在main函数外面零写一个函数以简化主函数的结构。刚开始架构程序的时候就要想清楚,如果边想边做会很浪费时间,因为会不停地修改,删除。
FIRST THINGS FIRST:关于on-line和off-line如何处理,书中代码是将其以1,0的方式存放在结构体中,这样在后面数据配对的时候会比较方便。
步骤:
①将读入的数据进行排序(排序要用到的就是这一节的sort函数,注意题目的排序优先顺序),
②根据题目说明的,每次输入一定会有配对的数据,且排序后这两个数据一定是紧挨着的。书中以on(初值为0),off的形式,再加一个next,令next在循环体中++的形式不断查找与On属于同一用户的on-line,off-line,并用needprint记录(0,1,2),这样结束循环后next指定的就是下一个用户了,然后判断needprint(这个只是判断有没有on-line, off-line),如果小于2,则说明这个用户没有配对数据,直接查找下一个用户的数据,令on=next, continue,否则的话,就开始把该用户的数据准备打印出来,注意on-line和off-line一定要连着出现才可以算成一组配对成功的数据。打印出来配对数据后就是计算钱了。这里的思路是写了个函数,这样main函数看起来很简洁。这个函数的思路其实前面出现过就是关于日期处理那一节的,不断令mm++,然后判断mm是否是60,然后判断hh是否为24。注意money打印出来要除100.0,因为题目给定的分钟资费单位是cent。注意循环内部打印每一组配对的资费,循环结束打印总的资费(实际上是仍在while内,两层循环)。
以下为代码:
发现书中代码有问题,找不到问题在哪,代码无法输出第三个人的数据。
暂时不知道问题在哪里我好笨。。。。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1010;
int toll[25];
struct Record{
char name[25];
int month, dd, hh, mm;
bool status;
}rec[maxn], temp;
bool cmp(Record a, Record b) {
int s=strcmp(a.name, b.name);
if(s!=0) return s<0;
else if(a.month!=b.month) return a.month<b.month;
else if(a.dd!=b.dd) return a.dd < b.dd;
else if(a.hh!=b.hh) return a.hh<b.hh;
else return a.mm<b.mm;
}
void get_ans(int on, int off, int &time, int&money){ //根据两个时间计算对应的钱
temp=rec[on];
while(temp.dd<rec[off].dd || temp.hh<rec[off].hh || temp.mm<rec[off].mm) {
time++;
money += toll[temp.hh];
temp.mm++;
if(temp.mm>=60) {
temp.hh++;
temp.mm=0;
}
if(temp.hh>=24) {
temp.dd++;
temp.hh=0;
}
}
}
int main() {
for(int i=0; i<24; i++) { //读入资费
scanf("%d", &toll[i]);
}
int n;
scanf("%d", &n);
char line[10];
for(int i=0; i<n; i++) {
scanf("%s %d:%d:%d:%d", rec[i].name, &rec[i].month, &rec[i].dd, &rec[i].hh, &rec[i].mm);
scanf("%s", line); //读入每行结尾的字符串
if(strcmp(line, "on-line")==0) { //判断是on还是off,并以true和false存放如结构体中
rec[i].status=true;
} else {
rec[i].status=false;
}
}
sort(rec,rec+n, cmp); //排序
int on =0, off, next;
while(on<n){
int needPrint=0; //表示该用户是否需要输出
next=on;
while(next<n && strcmp(rec[next].name, rec[on].name)==0) {
if(needPrint==0 && rec[next].status==true) {
needPrint=1;
} else if(needPrint=1 && rec[next].status==false) {
needPrint=2;
}
next++;
}
if(needPrint<2) {
on=next;
continue;
}
int Allmoney=0;
printf("%s %02d\n", rec[on].name, rec[on].month);
while(on < next) {
while(on<next-1
&& !(rec[on].status==true && rec[on+1].status==false)) {
on++;
}
off=on+1;
if(off==next) {
on=next;
break;
}
printf("%02d:%02d:%02d ", rec[on].dd, rec[on].hh, rec[on].mm);
printf("%02d:%02d:%02d ", rec[off].dd, rec[off].hh, rec[off].mm);
int time = 0, money=0;
get_ans(on, off, time, money);
Allmoney += money;
printf("%d $%.2f\n", time, money/100.0);
on = off + 1;
}
printf("Total amount: $%.2f\n", Allmoney/100.0);
}
return 0;
}
A1028List Sorting
已通过OJ
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct Student {
char id[8];
char name[10];
int grade;
};
bool cmp1(Student a, Student b) {
return strcmp(a.id, b.id)<0;
}
bool cmp2(Student a, Student b) {
if(strcmp(a.name, b.name)!=0) return strcmp(a.name, b.name)<0;
else return strcmp(a.id, b.id)<0;
}
bool cmp3(Student a, Student b) {
if(a.grade!=b.grade) return a.grade<b.grade;
else strcmp(a.id, b.id)<0;
}
int main() {
int N, C;
scanf("%d%d", &N, &C);
Student info[N];
for(int i=0; i<N; i++) {
scanf("%s %s %d", info[i].id, info[i].name, &info[i].grade);
}
switch (C) {
case 1:sort(info, info+N, cmp1); break;
case 2:sort(info, info+N, cmp2); break;
case 3:sort(info, info+N, cmp3);
}
for(int i=0; i<N; i++) {
printf("%s %s %d\n", info[i].id, info[i].name, info[i].grade);
}
return 0;
}
A1055 The World’s Richest
注意:sort不能写在后面那个大循环内部,否则有两个测试点会超时!
已通过OJ
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct Rich{
char name[10];
int age;
int wealth;
};
bool cmp(Rich a, Rich b) {
if(a.wealth!=b.wealth) return a.wealth>b.wealth;
else if(a.age!=b.age) return a.age<b.age;
else return strcmp(a.name, b.name)<0;
}
int main() {
int n, k;
scanf("%d%d", &n, &k);
Rich info[n];
for(int i=0; i<n; i++) {
scanf("%s %d %d", info[i].name, &info[i].age, &info[i].wealth);
}
sort(info, info+n, cmp);
for(int i=1; i<=k; i++) {
printf("Case #%d:\n", i);
int m, first, last; //m表示输出个数的最大值
scanf("%d%d%d", &m, &first, &last);
int count=0;
for(int j=0; j<n && m>0 ; j++) {
if(info[j].age>=first && info[j].age<=last) {
printf("%s %d %d\n", info[j].name, info[j].age, info[j].wealth);
m--;
count++;
}
}
if(count==0) printf("None\n");
}
return 0;
}
A1075 PAT Judge
问题:有三个测试点没有通过,找不到问题在哪里。
看了书中解答:发现问题有:
1.没有仔细读题,题目要求区分开来-全场没有提交记录—全都没有通过编译—有能通过编译的提交–
其中对于第一、二种情况是不需要打印的,对于第三种情况,无论提交通过后是否为零都需要打印,这是这道题的边界情况!!!
2.一开始是想着在结构体里面建立两个域no_com和no_sub,但是有问题,对于边界情况无法输出。书中是在结构体中定义了一个flag域,true表示有能通过编译的提交(即需要打印出来)。注意flag需要初始化位false
3.对于数组的初始化,除了使用循环赋值的方式外,还可以是使用memset函数来赋值,但由于这个函数是按字节赋值,最好只赋0和-1,避免出错,
memset(数组名, 值, sizeof(数组名));
以下为参考书中代码写的:
已通过OJ
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct Student {
int id;
int score[6];
int flag;
int total;
int rank;
int num;
};
bool cmp(Student a, Student b) {
if(a.total!=b.total) return a.total>b.total;
else if(a.num!=b.num) return a.num>b.num;
else return a.id<b.id;
}
int main() {
int n, k, m;
scanf("%d%d%d", &n, &k, &m);
Student info[n+1];
int full_mark[k+1];
for(int i=1; i<=k; i++) {
scanf("%d", &full_mark[i]);
}
for(int i=1; i<=n; i++) { //初始化
info[i].flag=false;
memset(info[i].score, -1, sizeof(info[i].score));
info[i].id=i;
}
while(m--) { //输入
int temp_id, temp_case, temp_score;
scanf("%d%d%d", &temp_id, &temp_case, &temp_score);
if(temp_score!=-1) {
info[temp_id].flag=true;
}
if(temp_score==-1 && info[temp_id].score[temp_case]==-1) {
info[temp_id].score[temp_case]=0;
}
if(info[temp_id].score[temp_case]<temp_score) {
info[temp_id].score[temp_case]=temp_score;
}
}
for(int i=1; i<=n; i++) { //计算总分及满分题数
info[i].total=0;
info[i].num=0;
for(int j=1; j<=k; j++) {
if(info[i].score[j]!=-1) {
info[i].total += info[i].score[j];
}
if(info[i].score[j]==full_mark[j]) {
info[i].num++;
}
}
}
sort(info+1, info+1+n, cmp);
info[1].rank=1;
for(int i=2; i<=n; i++) { //计算rank
if(info[i].total==info[i-1].total) {
info[i].rank=info[i-1].rank;
} else {
info[i].rank=i;
}
}
for(int i=1; i<=n; i++) {
if(info[i].flag==true) {
printf("%d %05d %d", info[i].rank, info[i].id, info[i].total);
for(int j=1; j<=k; j++) {
if(info[i].score[j]==-1) {
printf(" -");
} else {
printf(" %d", info[i].score[j]);
}
}
printf("\n");
}
}
return 0;
}
A1083 List Grades
已通过OJ
#include <cstdio>
#include <algorithm>
using namespace std;
struct Student {
char name[12];
char id[12];
int grade;
};
bool cmp(Student a, Student b) {
return a.grade>b.grade;
}
int main() {
int n;
scanf("%d", &n);
Student info[n];
for(int i=0; i<n; i++) {
scanf("%s %s %d", info[i].name, info[i].id, &info[i].grade);
}
sort(info, info+n, cmp);
int first, last;
scanf("%d%d", &first, &last);
int count=0;
for(int i=0; i<n; i++) {
if(info[i].grade>=first && info[i].grade<=last) {
printf("%s %s\n", info[i].name, info[i].id);
count ++;
}
}
if(count==0) {
printf("NONE\n");
}
return 0;
}
A1080 Graduate Admission----未解决 ✖
一组数据运行超时,估计是循环嵌套之后执行次数太多了。
发现把最后一个大循环拆开之后,还是无法通过,显示运行时错误
以下为提交代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
struct Student {
int id;
int ge, gi, total;
int rank;
int choices[6];
int final; //表示最后录取的学校的编号,初始化为-1
};
bool cmp(Student a, Student b) {
if(a.total!=b.total) return a.total>b.total;
else if(a.ge!=b.ge) return a.ge>b.ge;
}
int main() {
int n, m, k;
scanf("%d%d%d", &n, &m, &k);
int capacity[m];
for(int i=0; i<m; i++) {
scanf("%d", &capacity[i]);
}
Student info[n];
for(int i=0; i<n; i++) {
info[i].id=i; //初始化
info[i].final=-1; //初始化
memset(info[i].choices, -1, sizeof(info[i].choices)); //初始化
scanf("%d%d", &info[i].ge, &info[i].gi);
info[i].total = info[i].ge + info[i].gi;
for(int j=0; j<k; j++) { //读入学生的选择
scanf("%d", &info[i].choices[j]);
}
}
sort(info, info+n, cmp);
info[0].rank=1;
for(int i=1; i<n; i++) { //计算学生的rank
if(info[i].total==info[i-1].total && info[i].ge==info[i-1].ge) {
info[i].rank=info[i-1].rank;
} else {
info[i].rank=i+1;
}
}
int admission[m][n]={-1}; //用于保存被录取的学生的id
int rank[m]={0}; //用于记录每个学校最后录取的人的rank
for(int i=0; i<n; i++) { //开始录取操作
for(int j=0; j<k; j++) {
if(capacity[info[i].choices[j]]!=0) {
info[i].final=info[i].choices[j];
capacity[info[i].choices[j]]--;
if(capacity[info[i].choices[j]]==0) {
rank[info[i].choices[j]]=info[i].rank;
}
break;
} else if(info[i].rank==rank[info[i].choices[j]]) {
info[i].final=info[i].choices[j];
break;
}
}
}
int rear[m]={0}; //表示admission[]每行最后一个非-1元素的位序初始化为-1
for(int i=0; i<n; i++) {
if(info[i].final!=-1) {
admission[info[i].final][rear[info[i].final]]=info[i].id;
rear[info[i].final]++;
}
}
for(int i=0; i<m; i++) { //对其中的id进行排序,升序排列
sort(admission[i], admission[i]+rear[i]);
}
for(int i=0; i<m; i++) {
for(int j=0; j<rear[i]; j++) {
printf("%d", admission[i][j]);
if(j<rear[i]-1) printf(" ");
}
printf("\n");
}
return 0;
}
A1095Cars on Campus
问题:发现自己老是找不到自己写的代码的问题,自己的理解能力真的比较差。
自己写的代码不仅运行超时,而且有一个很大的问题,就是发现有一个数据对不上。
服了,自己写的代码又臭又长还不对。
终于知道自己写的代码有问题的原因了,题目要求是把一辆车总的时间打印出来,我只考虑了一次最长时间,没有把相同车牌号的时间加起来!
以下为书中代码:
注意:本题用到了stl容器中的map:以下为详细介绍
This is a ink
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <algorithm>
using namespace std;
const int maxn=10010;
struct Car{
char id[8];
int time;
char status[4];
}all[maxn], valid[maxn];
int num=0;
map<string, int> parktime; //车牌号->总停留时间
int timetoint(int hh, int mm, int ss) {
return hh*3600+mm*60+ss;
}
bool cmp1(Car a, Car b) {
if(strcmp(a.id, b.id)!=0) return strcmp(a.id, b.id)<0;
else return a.time<b.time;
}
bool cmp2(Car a, Car b) {
return a.time<b.time;
}
int main() {
int n, k, hh, mm, ss;
scanf("%d%d", &n, &k);
for(int i=0; i<n; i++) {
scanf("%s %d:%d:%d %s", all[i].id, &hh, &mm, &ss, all[i].status);
all[i].time=timetoint(hh, mm, ss);
}
sort(all, all+n, cmp1);
int maxtime=-1;
for(int i=0; i<n-1; i++) {
if(!strcmp(all[i].id, all[i+1].id) && !strcmp(all[i].status, "in") && !strcmp(all[i+1].status, "out")) {
valid[num++]=all[i];
valid[num++]=all[i+1];
int intime=all[i+1].time-all[i].time;
if(parktime.count(all[i].id)==0) {
parktime[all[i].id]=0;
}
parktime[all[i].id] +=intime;
maxtime=max(maxtime, parktime[all[i].id]);
}
}
sort(valid, valid+num, cmp2);
int now=0, nowcar=0;
for(int i=0; i<k; i++) {
scanf("%d:%d:%d", &hh, &mm, &ss);
int time=timetoint(hh, mm, ss);
while(now<num && valid[now].time<=time) {
if(!strcmp(valid[now].status, "in")) {
nowcar++;
}
else {
nowcar--;
}
now++;
}
printf("%d\n", nowcar);
}
map<string, int>::iterator it;
for(it=parktime.begin(); it!=parktime.end(); it++) {
if(it->second==maxtime) {
printf("%s ", it->first.c_str());
}
}
printf("%02d:%02d:%02d\n", maxtime/3600, maxtime%3600/60, maxtime%60);
return 0;
}
A 1041Be Unique
emmm, 暴力AC.
已通过OJ
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxsize=10010;
struct Number{
int num, order, times;
}hashtable[maxsize];
bool cmp(Number a, Number b) {
if(a.times!=b.times) return a.times<b.times;
else return a.order<b.order;
}
int main() {
int n;
scanf("%d", &n);
for(int i=0; i<maxsize; i++) { //初始化
hashtable[i].num=0;
hashtable[i].order=0;
hashtable[i].times=0;
}
for(int i=1; i<=n; i++) {
int temp;
scanf("%d", &temp);
if(hashtable[temp].times==0) {
hashtable[temp].num=temp;
hashtable[temp].order=i;
}
hashtable[temp].times ++;
}
sort(hashtable, hashtable+maxsize, cmp);
for(int i=0; i<maxsize; i++) {
if(hashtable[i].times==1) {
printf("%d\n", hashtable[i].num);
break;
} else if(hashtable[i].times>1) {
printf("None\n");
break;
}
}
return 0;
}
总结:1.此题其实很简单的,只需要在对hashtable[]++的过程中,把输入的数据按顺序保存在数组里就好了,这样在输入结束后,就可以直接按输入顺序查找hashtable[]==1的点。
以下为书中代码。(我好蠢呀)
#include <cstdio>
int a[100010], hashtable[10010]={0};
int main() {
int n;
scanf("%d", &n);
for(int i=0; i<n; i++) {
scanf("%d", &a[i]);
hashtable[a[i]]++;
}
int ans=-1;
for(int i=0; i<n; i++) {
if(hashtable[a[i]]==1) {
ans=a[i];
break;
}
}
if(ans!=-1) {
printf("%d\n", ans);
} else {
printf("None\n");
}
return 0;
}
A1050 String Subtraction
注意:1.visible ASCII:首先不可见ASCII字符是ASCII中的控制字符,即ASCII在0-31及127的字符,剩下的就全部都是visible ASCII, 常见的大小写字母,数字0-9,等等。
2.注意以后写循环尽量不要写i<strlen(s1),因为函数strlen()每循环一次都会调用一次,而该函数的时间复杂度为O(n),每次调用会延长循环运行时间,容易导致超时。
3.如果引用了iostream或者vector, 又加了using namepsace std的话,尽量不要用hush作为变量名,还有math.h中的y1。
已通过OJ
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxsize=10010;
char s1[maxsize], s2[maxsize];
bool hashtable[128];
int main() {
cin.getline(s1, maxsize);
cin.getline(s2, maxsize);
memset(hashtable, true, sizeof(hashtable));
int len1=strlen(s1);
int len2=strlen(s2);
for(int i=0; i<len2; i++) {
if(hashtable[s2[i]]==true) {
hashtable[s2[i]]=false;
}
}
for(int i=0; i<len1 ; i++) {
if(s1[i]=='.' && hashtable['.']==true) {//
printf(".\n");//
break;//
}//上面这几步可以不写,题目没有这个意思,属于误解。
if(hashtable[s1[i]]==true) {
printf("%c", s1[i]);
}
}
return 0;
}
A1048 Find Coins----也可用二分查找、two pointers方法解决-待解决❌
注意:由于每个硬币面值小于等于500,且m的值小于等于1000, 因此若设hashtable[510],有可能会出现m-ans大于510的情况,导致段错误,所以,为了避免这种情况,要将hashtable尽量设大些,且要大于1000,如1001.
已通过OJ
#include <cstdio>
const int maxsize=1001;
int hashtable[maxsize]={0};
int ans;
int n, m;
int main() {
scanf("%d%d", &n, &m);
for(int i=0; i<n; i++) {
int temp;
scanf("%d", &temp);
hashtable[temp]++;
}
ans=510;
for(int i=1; i<maxsize; i++) {
if(hashtable[i]>0) {
hashtable[i]--;
if(hashtable[m-i]>0) {
ans=i;
}
hashtable[i]++;
}
}
if(ans!=510) {
if(ans>m-ans) {
ans=m-ans;
}
printf("%d %d\n", ans, m-ans);
} else {
printf("No Solution\n");
}
return 0;
}
A1033 To Fill or Not to Fill
思路:1.把终点视为单位油价是0,距离起点为d的加油站,这样就可以把终点放在循环里面进行,不用进行特殊情况的讨论。注意第一个边界情况,若离起点最近的加油站距离不是0,则表示汽车无法出发,应该打印相应的语句直接输出!
2.从当前加油站寻找下一个加油站的策略:–贪心
两种可能性:①寻找离现在的加油站最近的且价格比当前加油站价格小的站点, 找到后,加恰好能到达这个站点的油。若没有,则
②寻找油价最低的站点(当然要在加满油能跑的距离内),在当前站点加满油,然后前往下一个站点。
3)若在满油状况下也找不到这样的站点,则直接break,打印相应的语句表明无法到达目的地!这是第二个边界情况
以下为书中代码:
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=510;
const int inf=1000000000;
struct Station {
double price, dis;
}st[maxn];
bool cmp(Station a, Station b) {
return a.dis<b.dis; //这里应该是不需要考虑离出发点相同距离的汽油站这种情况
}
int main() {
int n;
double cmax, d, davg;
scanf("%lf%lf%lf%d", &cmax, &d, &davg, &n);
for(int i=0; i<n; i++) {
scanf("%lf%lf", &st[i].price, &st[i].dis);
}
st[n].price=0;
st[n].dis=d;
sort(st, st+n, cmp);
if(st[0].dis!=0) { //处理边界情况
printf("The maximum travel distance = 0.00\n");
} else {
int now=0;
double ans=0, nowtank=0, max=cmax*davg;
while(now<n) {
int k=-1;
double pricemin=inf;
for(int i=now+1; i<=n && st[i].dis-st[now].dis<=max; i++) { //寻找当前范围内油价最低的加油站
if(st[i].price<pricemin) {
pricemin=st[i].price;
k=i;
if(pricemin<st[now].price) {
break;
}
}
}
if(k==-1) { //到不了下一个加油站,便退出循环,直接打印开的最大距离
break;
}
double need=(st[k].dis-st[now].dis)/davg;
if(pricemin<st[now].price) { //第一种可能性
if(nowtank<need) {
ans += (need-nowtank)*st[now].price;
nowtank=0;
}else {
nowtank -= need;
}
} else { //第二种可能性
ans += (cmax-nowtank) * st[now].price;
nowtank=cmax-need;
}
now=k;
}
if(now==n) {
printf("%.2f\n", ans);
} else {
printf("The maximum travel distance = %.2f\n", st[now].dis+max);// 注意加上满油能跑的最大距离!
}
}
return 0;
}
A1037 Magic Coupon
问题:有两个测试点未通过,一开始以为是int型数据可能出现溢出的,修改为long long之后还是无法通过这两个测试点!
服了!我没对product[]进行排序,而是把coupon[]排了两次,这种小问题居然都差点没找到!我好笨啊啊啊啊 !
已通过OJ
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=100010;
long long coupon[maxn], product[maxn];
bool cmp(int a, int b) {
return a>b;
}
int main() {
int Nc, Np;
scanf("%d", &Nc);
for(int i=0; i<Nc; i++) {
scanf("%lld", &coupon[i]);
}
scanf("%d", &Np);
for(int i=0; i<Np; i++) {
scanf("%lld", &product[i]);
}
sort(coupon, coupon+Nc, cmp);
sort(product, product+Np, cmp);
long long ans=0; //最终得到的钱
for(int i=0; i<Nc && i<Np; i++) { //先把所有乘起来是正数的加起来
if(coupon[i]>0 && product[i]>0) {
ans += coupon[i]*product[i];
} else {
break;
}
}
int j=Nc-1, k=Np-1; //然后反向找乘起来是正数的对应元素,并加起来
while(coupon[j]<0 && product[k]<0) {
ans += coupon[j]*product[k];
j--;k--;
}
printf("%lld\n", ans);
return 0;
}
A1067 Sort with Swap(0, i)
思路:1.可以想到的是每次把零号位与零号位所占位置原本的数的位置进行交换,即swap(pos[0], pos[pos[0]]),注意,这里定义的是pos[数字]=位序,也就是说每次交换的是两个数字的位序。
2.使用left记录除零外不在本位上的数字的个数,初始记为n-1,在循环输入的时候,可以判断并–,最终得到的肯定是不在位数,除零之外。
left也将作为循环的出口。
已通过OJ
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=100010;
int pos[maxn];
int main() {
int n, ans=0;
scanf("%d", &n);
int left=n-1, num; //left存放数字不在其本位上的数的个数
for(int i=0; i<n; i++) {
scanf("%d", &num);
pos[num]=i; //将读入的数作为下标,以其读入顺序作为值保存在数组中
if(num==i && num!=0) {
left--;
}
}
int k=1; //用来存放除0之外不在本位上的最小的数
while(left>0) {
if(pos[0]==0) {
while(k<n) { //这个循环是为了找到当零在0号位时,不在本位上的最小的数
if(pos[k]!=k) {
swap(pos[0], pos[k]);
ans++;
break;
}
k++;
}
}
while(pos[0]!=0) {
swap(pos[0], pos[pos[0]]); //pos[pos[0]]表示0所在的位置的本位在哪个位置并与之交换!
ans++;
left--;
}
}
printf("%d\n", ans);
return 0;
}
A1038Recover the Smallest Number
A 1010 Radix-----一个问题❌
问题总结:1.对于二分算法还不是特别熟悉,要更加熟练地写出来。
2.关于其他进制转十进制地算法也给忘了,其实很简单的,ans = ans*radix + a[i],循环计算即可
3.书中没有考虑如果解不唯一的情况,应该这么理解,如果二分找到了和n1相等的进制,那么比这个小的进制一定小于n1,比这个大的进制一定大于n1,也就是说这种情况是不会出现的(?!);
4.关于二分的上界的问题,一开始我以为只到36,因为题目给的0-9, a-z刚好到了35,但是并不是这么理解的,真实情况是进制可以很大,甚至还要考虑到转为10进制后会不会溢出的情况。书中给的上界说是max(n1的进制,n2的下界)+1,原因还不太清楚!
5.
已通过OJ
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
LL Map[256];
LL inf=(1LL<<63)-1;
void init() {
for(char c='0'; c<='9'; c++) {
Map[c]=c-'0';
}
for(char c='a';c<='z'; c++) {
Map[c]=c-'a'+10;
}
}
LL convertoNum10(char a[], LL radix, LL t) {
LL ans=0;
int len=strlen(a);
for(int i=0; i<len; i++) {
ans = ans*radix+Map[a[i]];
if(ans<0 || ans>t) return -1; //溢出或超过N1的十进制
}
return ans;
}
int cmp(char N2[], LL radix, LL t) { //N2的十进制与t比较
int len=strlen(N2);
LL num=convertoNum10(N2, radix, t);
if(num<0) return 1;
if(t>num) return -1;
else if(t==num) return 0;
else return 1;
}
LL binarySearch(char N2[], LL left, LL right, LL t) {
LL mid;
while(left<=right) {
mid=(left+right)/2;
int flag=cmp(N2, mid, t);
if(flag==0) return mid;
else if(flag==1) {
right=mid-1;
} else {
left=mid+1;
}
}
return -1;
}
int findLargestDist(char N2[]) {
int ans=-1, len=strlen(N2);
for(int i=0; i<len; i++) {
if(Map[N2[i]]>ans) {
ans=Map[N2[i]];
}
}
return ans+1;
}
char N1[20], N2[20], temp[20];
int tag, radix;
int main() {
init();
scanf("%s %s %d %d", N1, N2, &tag, &radix);
if(tag==2) {
strcpy(temp, N1);
strcpy(N1, N2);
strcpy(N2,temp);
}
LL t=convertoNum10(N1, radix, inf);
LL low=findLargestDist(N2);
LL high=max(low, t)+1;
LL ans=binarySearch(N2, low, high, t);
if(ans==-1) printf("Impossible\n");
else printf("%lld\n", ans);
return 0;
}
A1044 Shopping in Mars
总结:1.正确理解uppere_bound()函数的使用及其内核;
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=100010;
int nearm=100000010;
int n,m, k=0;
int sum[maxn]={0};
int upper_bound(int l, int r, int x) {
int mid;
while(l<r) {
mid=(l+r)/2;
if(sum[mid]>x) {
r=mid;
}else {
l=mid+1;
}
}
return l;
}
int main() {
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++) { //把钻石序列逐个叠加
scanf("%d", &sum[i]);
sum[i] += sum[i-1];
}
for(int i=1; i<=n; i++) { //寻找第一个大于m的位置
int j=upper_bound(i, n+1, m+sum[i-1]);
if(sum[j-1]-sum[i-1]==m) {
nearm=m;
break;
} else if(j<=n && sum[j]-sum[i-1]<nearm) {
nearm=sum[j]-sum[i-1];
}
}
for(int i=1; i<=n; i++) {
int j=upper_bound(i, n+1, sum[i-1]+nearm);
if(sum[j-1]-sum[i-1]==nearm) {
printf("%d-%d\n", i, j-1);
}
}
return 0;
}
A1089 Insert or Merge
总结:1.对插入排序的实现还不熟悉,要在理解的基础上记忆!
2.归并排序在0-n的实现
3.在写代码的时候如果有一段函数多次出现,可以尽量用一个函数封装,这样可以让代码逻辑思路非常清晰!
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=110;
int n, origin[maxn], partsort[maxn], temp[maxn];
bool isSame(int a[], int b[]) {
for(int i=0; i<n; i++) {
if(a[i]!=b[i]) {
return false;
}
}
return true;
}
void showArray(int a[]) {
for(int i=0; i<n; i++) {
printf("%d", a[i]);
if(i<n-1) printf(" ");
}
printf("\n");
}
//插入排序应该要会写的
bool insertSort() {
bool flag=false;
for(int i=1; i<n; i++) {
if(i!=1 && isSame(temp, partsort)) {
flag=true;
}
int tem=temp[i], j=i;
while(j>0 && temp[j-1]>tem) {
temp[j]=temp[j-1];
j--;
}
temp[j]=tem;
if(flag==true) {
return true;
}
}
return false;
}
void mergeSort() {
bool flag=false;
for(int step=2; step/2<=n; step*=2) {
if(step!=2 && isSame(temp, partsort)) {
flag=true;
}
for(int i=0; i<n; i+=step) {
sort(temp+i, temp+min(i+step, n));
}
if(flag==true) {
showArray(temp);
return;
}
}
}
int main() {
scanf("%d", &n);
for(int i=0; i<n; i++) {
scanf("%d", &origin[i]);
temp[i]=origin[i];
}
for(int i=0; i<n; i++) {
scanf("%d", &partsort[i]);
}
if(insertSort()) {
printf("Insertion Sort\n");
showArray(temp);
} else {
printf("Merge Sort\n");
for(int i=0; i<n; i++) {
temp[i]=origin[i];
}
mergeSort();
}
return 0;
}
A1029 median
问题:书中代码有问题,最后一个测试点无法通过,查询后发现原因是由于数据太大,不可以全部读入后再处理数据,必须读完第一个数组然后第二个数组边读入边处理。
这是别人的AC代码link?
总结:1.STL容器queue的使用
2.#include < climits >:
定义了各种数据类型的最值常量:
如:
INT_MAX int 最大值
INT_MIN int 最小值
A 1093 count PAT’S
总结:1.这种题肯定不可以暴力求解的,必然超时
2.思考解决方案的时候多动动脑子?,那么多沟咋就用不上呢?迷思
3.对于这道题,关键是要想到计算A左边的P和右边的T,且P用了一个数组来记录该数左边的p的个数,这样才不会超时!
以下为书中代码:
#include <cstdio>
#include <cstring>
const int maxn=100010;
const int mod=1000000007;
char str[maxn];
int leftnumP[maxn]={0};
int main() {
scanf("%s", str);
int len=strlen(str);
for(int i=0; i<len; i++) {
if(i>0) {
leftnumP[i]=leftnumP[i-1];
}
if(str[i]=='P') {
leftnumP[i]++;
}
}
int ans=0, rightNumT=0;
for(int i=len-1; i>=0; i--) {
if(str[i]=='T') {
rightNumT++;
} else if(str[i]=='A') {
ans = (ans + leftnumP[i]*rightNumT)%mod;
}
}
printf("%d\n", ans);
return 0;
}
A1101
此题与上一道题思想是一样的,都是开数组,然后对应的位置记录原数组的大小。关系之类的,此题得同时从数组两端遍历形成两个数组。
以下为书中代码:
#include <cstdio>
#include <climits>
#include <algorithm>
using namespace std;
const int maxn=100010;
int a[maxn], leftmax[maxn], rightmin[maxn];
int ans[maxn], num=0;
int main() {
int n;
scanf("%d", &n);
for(int i=0; i<n; i++) {
scanf("%d", &a[i]);
}
leftmax[0]=0;
for(int i=1; i<n; i++) {
leftmax[i]=max(leftmax[i-1], a[i-1]);
}
rightmin[n-1]=INT_MAX;
for(int i=n-2; i>=0; i--) {
rightmin[i]=min(rightmin[i+1], a[i+1]);
}
for(int i=0; i<n; i++) {
if(leftmax[i]<a[i] && a[i]<rightmin[i]) {
ans[num++]=a[i];
}
}
sort(ans, ans+num);
printf("%d\n", num);
for(int i=0; i<num; i++) {
printf("%d", ans[i]);
if(i<num-1) printf(" ");
}
printf("\n");
return 0;
}
A 1069
已通过OJ
根据书中代码对自己的代码做了一些局部优化,这样看起来逻辑更加清晰!
#include <cstdio>
#include <algorithm>
using namespace std;
int n;
int digits[4]={0};
bool cmp(int a, int b) {
return a>b;
}
int return4int(int a[]) {
int ans=0;
for(int i=0; i<4; i++) {
ans = ans*10 + a[i];
}
return ans;
}
int returntoArray(int ans) {
int num=0;
do{
digits[num++]=ans%10;
ans/=10;
}while(ans>0);
}
int main() {
scanf("%d", &n);
int ans=n, ascend, descend;
do{
returntoArray(ans);
sort(digits, digits+4); //digits变成了升序
ascend=return4int(digits);
sort(digits, digits+4, cmp);
descend=return4int(digits);
ans=descend-ascend;
printf("%04d - %04d = %04d\n", descend, ascend, ans);
}while(ans!=0 && ans!=6174);
return 0;
}
A 1008
#include <cstdio>
int up=6, down=4, stop=5;
int main() {
int n;
scanf("%d", &n);
int a, pre=0;
int total=0;
while(n--) {
scanf("%d", &a);
if(a<pre) {
total+=(pre-a)*down;
} else {
total+=(a-pre)*up;
}
total+=stop;
pre=a;
}
printf("%d\n", total);
return 0;
}
A1081
有一组数据运行超时,发现原因是循环内的一组判断语句导致的超时,估计是输入数据太多了引起的!
已通过OJ
#include <cstdio>
#include <algorithm>
using namespace std;
typedef struct{
long long up, down;
}Fraction;
long long gcd(int a, int b) {
// if(a<b) {
// int temp=a;
// a=b;
// b=temp;
// }
return !b ?a:gcd(b, a%b);
}
Fraction reduction(Fraction result) {
if(result.down<0) {
result.down*=-1;
result.up*=-1;
}
if(result.up==0) {
result.down=1;
} else {
int temp=gcd(abs(result.up), result.down);
result.down/=temp;
result.up/=temp;
}
return result;
}
Fraction Add(Fraction a, Fraction b) {
Fraction result;
result.down=a.down*b.down;
result.up=a.up*b.down+b.up*a.down;
return reduction(result);
}
void Output(Fraction r) {
Fraction result=reduction(r);
if(result.down==1) {
printf("%lld\n", result.up);
} else if(abs(result.up)>result.down) {
printf("%lld %lld/%lld\n", result.up/result.down,
abs(result.up)%result.down, result.down);
} else {
printf("%lld/%lld\n", result.up, result.down);
}
}
int main() {
int n;
scanf("%d", &n);
Fraction sum,temp;
sum.down=1;sum.up=0;
while(n--) {
scanf("%lld/%lld", &temp.up, &temp.down);
sum=Add(sum, temp);
}
Output(sum);
return 0;
}
A1088
问题:输出函数里面当为假分数的时候,计算分母忘记取绝对值了
已通过OJ:
#include <cstdio>
#include <algorithm>
using namespace std;
char operators[4]={'+', '-', '*', '/'};
typedef struct{
long long up, down;
}Fraction;
long long gcd(long long a, long long b) {
return !b?a:gcd(b, a%b);
}
Fraction reduction(Fraction result) {
if(result.down<0) {
result.down*=-1;
result.up*=-1;
}
if(result.up==0) {
result.down=1;
} else {
long long temp=gcd(abs(result.up), abs(result.down));
result.down/=temp;
result.up/=temp;
}
return result;
}
Fraction Add(Fraction a, Fraction b) {
Fraction sum;
sum.down=a.down*b.down;
sum.up=a.up*b.down+a.down*b.up;
return reduction(sum);
}
Fraction Difference(Fraction a, Fraction b) {
Fraction differ;
differ.down=a.down*b.down;
differ.up=a.up*b.down-b.up*a.down;
return reduction(differ);
}
Fraction Product(Fraction a, Fraction b) {
Fraction result;
result.down=a.down*b.down;
result.up=a.up*b.up;
return reduction(result);
}
Fraction Quotient(Fraction a, Fraction b) {
Fraction result;
result.down=a.down*b.up;
result.up=a.up*b.down;
return reduction(result);
}
void Output(Fraction a){
Fraction result=reduction(a);
if(result.up<0) printf("(");
if(result.down==1) {
printf("%lld", result.up);
} else if(abs(result.up)>result.down) {
printf("%lld %lld/%lld", result.up/result.down,
abs(result.up)%result.down, result.down);
} else {
printf("%lld/%lld", result.up, result.down);
}
if(result.up<0) printf(")");
}
int main() {
Fraction a, b, result;
scanf("%lld/%lld %lld/%lld", &a.up, &a.down, &b.up, &b.down);
for(int i=0; i<4; i++) {
Output(a);
printf(" %c ", operators[i]);
Output(b);
printf(" = ");
if(i==3 && b.up==0) {
printf("Inf\n");
break;
}
switch(i) {
case 0: result=Add(a, b); break;
case 1: result=Difference(a, b); break;
case 2: result=Product(a, b); break;
case 3: result=Quotient(a, b);
}
Output(result);
printf("\n");
}
return 0;
}
A 1078
问题:1.有一个测试点无法通过!
原因初步估计为平方探测的函数没有对msize取模,其实是不知道怎么破无限循环=.=,所以直接把取模给删了,结果一个测试点无法通过
解决方法:事实上只要step(代码里以j表示)<msize,就可以认为这个数无法插入了!因此循环条件是hashtable[H1]==true && j<msize
以下为代码,已通过OJ
#include <cstdio>
#include <cmath>
const int maxn=10010;
bool hashtable[maxn]={false};
bool isPrime(int n) {
if(n<=1) return false;
int sqr=(int) sqrt(n);
for(int i=2; i<=sqr; i++) {
if(n%i==0) return false;
}
return true;
}
int main() {
int msize, n;
scanf("%d%d", &msize, &n);
while(isPrime(msize)==false) {
msize++;
}
for(int i=0; i<n; i++) {
int temp;
scanf("%d", &temp);
int H0=temp%msize;
if(hashtable[H0]==false) {
hashtable[H0]=true;
printf("%d", H0);
} else {
int j=1, H1=H0;
while(hashtable[H1]==true && j<msize) {
H1 =(H0+j*j)%msize;
j++;
}
if(hashtable[H1]==false) {
printf("%d", H1);
hashtable[H1]=true;
} else {
printf("-");
}
}
if(i<n-1) printf(" ");
}
return 0;
}
A 1059
问题:1.打印质因子的算法还不太理解,步骤是:对小于sqrt(n)的质数进行枚举,如果n/prime[i]0 说明该数为其因数,因此将其加入到fac[]中,并置cnt=0, 然后进入循环判断该质数作为n的因子出现了几次,即一直令n/=prime[i],直到prime[i]不为其因子为止,注意如果上面的循环结束后出现n1, 则立刻跳出循环.循环结束后判断n是否为1,若不是1,则把该数加入到fac[]中,令其个数为1.
2.打印素数表的算法,注意在整型范围内,令其maxsize为100010即可,可以用暴力法,也可以用埃氏法枚举
3.注意n=1时要特判输出
以下为代码:参考书本优化:
#include <cstdio>
#include <cmath>
bool isPrime(int n) {
if(n<=1) return false;
int sqr=(int) sqrt(1.0*n);
for(int i=2; i<=sqr; i++) {
if(n%i==0) return false;
}
return true;
}
const int maxn=100010; //整型范围内10^5即可
int primes[maxn],pnum=0;
void get_prime() {
for(int i=1; i<maxn; i++) {
if(isPrime(i)==true) {
primes[pnum++]=i;
}
}
}
struct factor{
int x, count;
}fac[10];
int main() {
int n, num=0;
get_prime();
scanf("%d", &n);
printf("%d=", n);
if(n==1) {
printf("1");
} else {
int sqr=(int) sqrt(n*1.0);
for(int i=0; i<pnum && primes[i]<=sqr; i++) {
if(n%primes[i]==0) {
fac[num].x=primes[i];
fac[num].count=0;
while(n%primes[i]==0) {
fac[num].count++;
n/=primes[i];
}
num++;
}
if(n==1) break;
}
if(n!=1) {
fac[num].x=n;
fac[num++].count=1;
}
for(int i=0; i<num; i++) {
if(i>0) printf("*");
printf("%d", fac[i].x);
if(fac[i].count>1) {
printf("^%d", fac[i].count);
}
}
}
return 0;
}
A 1096
总结:1.一开始没有想清楚,一点思路都没有!
2.柳神的代码思路:首先如果一个数只有一个因子,那么这个数一定是1或质数;其次==在两个及以上的连乘中,因数的最大上限必为sqrt(n),
以下为柳神代码:好简洁鸭!
#include <iostream>
#include <cmath>
using namespace std;
long int num, temp;
int main() {
cin >> num;
int first=0, len=0, maxn=sqrt(num);
for(int i=2; i<=maxn; i++) {
int j;temp=1;
for(j=i; j<=maxn; j++) {
temp*=j;
if(num%temp!=0) break;
}
if(j-i>len) {
len=j-i;
first=i;
}
}
if(first==0) cout << 1 << endl << num;
else {
cout << len << endl;
for(int i=0; i<len; i++) {
cout << first+i;
if(i!=len-1) cout << '*';
}
}
return 0;
}
A1023
总结:1.对于高精度的加减乘除还不是很熟练,需要多看多做!
#include <cstdio>
#include <cstring>
struct bign{
int d[1000];
int len;
bign() {
memset(d, 0, sizeof(d));
len=0;
}
};
int hashtable[10]={0};
bign multi(bign a, int b) {
bign c;
int carry=0;
for(int i=0; i<a.len; i++) {
int temp=b*a.d[i]+carry;
c.d[c.len++]=temp%10;
carry=temp/10;
}
while(carry!=0) {
c.d[c.len++]=carry%10;
carry/=10;
}
return c;
}
int main() {
char A[20];
scanf("%s", A);
int len=strlen(A);
bign m, ans;
m.len=len;
for(int i=0; i<m.len; i++) {
m.d[i]=A[len-i-1]-'0';
hashtable[A[len-i-1]-'0']++;
}
ans=multi(m, 2);
int i;
for(i=0; i<ans.len; i++) {
if(hashtable[ans.d[i]]>0) {
hashtable[ans.d[i]]--;
} else {
printf("No\n");
break;
}
}
if(i==ans.len) {
printf("Yes\n");
}
for(int j=ans.len-1; j>=0; j--) {
printf("%d", ans.d[j]);
}
return 0;
}
注意:代码虽然过了测试,但好像不太严谨,没有考虑两个数位数不等的情况,书中的代码更加严谨
这是判断b的位是否为a的全排列的一种方式!
bool Judge(bign a, bign b) {
if(a.len!=b.len) return false;
int count[10]={0};
for(int i=0; i<a.len; i++) {
count[a.d[i]]++;
count[b.d[i]]--;
}
for(int i=0; i<10; i++) {
if(count[i]!=0) {
return false;
}
}
return true;
}
A 1024
问题:1.有两个测试点没有通过,不知道是什么边界条件未考虑!
原因:高精度数的数组开小了,虽然题目给定的数在1010 以内,但考虑到N的操作,最好开大些,不要这么小气!
已通过OJ
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1000;
struct bign{
int d[maxn];
int len;
bign() {
memset(d, 0, sizeof(d));
len=0;
}
};
bign add(bign a, bign b) {
bign c;
int carry=0;
for(int i=0; i<a.len || i<b.len; i++) {
int temp=a.d[i]+b.d[i]+carry;
c.d[c.len++]=temp%10;
carry=temp/10;
}
if(carry!=0) {
c.d[c.len++]=carry;
}
return c;
}
bool isPalindromic(bign a) {
int len=a.len;
for(int i=0; i<=len/2; i++) {
if(a.d[i]!=a.d[len-i-1]) {
return false;
}
}
return true;
}
void Output(bign a) {
for(int i=a.len-1; i>=0; i--) {
printf("%d", a.d[i]);
}
}
int main() {
char str[maxn];
int k, count=0;
scanf("%s %d", str, &k);
int len=strlen(str);
bign origin;
origin.len=len;
for(int i=0;i<len; i++) {
origin.d[len-i-1]=str[i]-'0';
}
bign sum=origin;
while(count<k && isPalindromic(sum)==false) {
bign rever=sum;
reverse(rever.d, rever.d+rever.len);
count++;
sum=add(rever, sum);
}
Output(sum);
printf("\n%d\n", count);
return 0;
}
A 1039
总结:1.使用hash(262626*10+1)将学生姓名映射为一个整数
2.vector的使用:
本题使用的是vector < int > v[maxn];
其中v[i]代表第i个vector,而i就可以用上面映射的整数来表示
以下为书中代码:
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int n=40010;
const int m=26*26*26*10+1;
vector<int> selectcourse[m];
int getID(char name[]) {
int id=0;
for(int i=0; i<3; i++) {
id = id*26+(name[i]-'A');
}
id=id*10+name[3]-'0';
return id;
}
int main() {
char name[5];
int n, k;
scanf("%d%d", &n, &k);
for(int i=0; i<k; i++) {
int course, x;
scanf("%d%d", &course, &x);
for(int j=0; j<x; j++) {
scanf("%s", name);
int id=getID(name);
selectcourse[id].push_back(course);
}
}
for(int i=0; i<n; i++) {
scanf("%s", name);
int id=getID(name);
sort(selectcourse[id].begin(), selectcourse[id].end());
printf("%s %d", name, selectcourse[id].size());
for(int j=0; j<selectcourse[id].size(); j++) {
printf(" %d", selectcourse[id][j]);
}
printf("\n");
}
return 0;
}
A 1047
这道题就是上面这道题反过来,但是发现如果直接用string存的话最后一组数据还是会超时,
总结:1.当数据量很大时,注意少用string,可能非常容易超时!!!!考虑使用字符数组!
以下为书中代码:
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=40010;
const int maxc=2510;
char name[maxn][5];
vector<int> course[maxn];
bool cmp(int a, int b) {
return strcmp(name[a], name[b])<0;
}
int main() {
int n, k, c, courseID;
scanf("%d%d", &n, &k);
for(int i=0; i<n; i++) {
scanf("%s %d", name[i], &c);
for(int j=0; j<c; j++) {
scanf("%d", &courseID);
course[courseID].push_back(i);
}
}
for(int i=1; i<=k; i++) {
printf("%d %d\n", i, course[i].size());
sort(course[i].begin(), course[i].end(), cmp);
for(int j=0; j<course[i].size(); j++) {
printf("%s\n", name[course[i][j]]);
}
}
return 0;
}
A 1063
总结:有时候没有其他办法只能枚举的时候也不要犹豫,直接写即可!
以下为参考书中的代码:
#include <cstdio>
#include <set>
using namespace std;
const int maxset=60;
set<int> sets[maxset];
void compare(int x, int y) {
int total=sets[y].size(), same=0;
for(set<int>::iterator it=sets[x].begin(); it!=sets[x].end(); it++) {
if(sets[y].find(*it)!=sets[y].end()) {
same++;
} else {
total++;
}
}
printf("%.1f%\n", same*100.0/total);
}
int main() {
int n, m, k, a, b, num;
scanf("%d", &n);
for(int i=1; i<=n; i++) {
scanf("%d", &m);
for(int j=0; j<m; j++) {
scanf("%d", &num);
sets[i].insert(num);
}
}
scanf("%d", &k);
for(int i=0; i<k; i++) {
scanf("%d%d",&a, &b);
compare(a, b);
}
return 0;
}
A 1060-------重要-关于科学记数法,string
以下为书中代码:
#include <cstdio>
#include <string>
#include <iostream>
using namespace std;
int n;
string deal(string s, int &e) {
int k=0;
while(s.length()>0 && s[0]=='0') {
s.erase(s.begin());
}
if(s[0]=='.') {
s.erase(s.begin());
while(s.length()>0 && s[0]=='0') {
s.erase(s.begin());
e--;
}
} else {
while(k<s.length() && s[k]!='.') {
k++;
e++;
}
if(k<s.length()) {
s.erase(s.begin()+k);
}
}
if(s.length()==0) {
e=0;
}
int num=0;
k=0;
string res;
while(num<n) {
if(k<s.length()) res += s[k++];
else res+='0';
num++;
}
return res;
}
int main() {
string s1, s2, s3, s4;
cin >> n >> s1 >> s2;
int e1=0, e2=0;
s3=deal(s1, e1);
s4=deal(s2, e2);
if(s3==s4 && e1==e2) {
cout << "YES 0." << s3 << "*10^" << e1 << endl;
} else {
cout << "NO 0." << s3 << "*10^" << e1 << " 0." << s4 << "*10^" << e2 << endl;
}
return 0;
}
总结:1.题目隐含了一个问题:数字前面可能会有多余的前导零,注意!
A1100–关于map
总结:1.这道题由于数据不大,可以考虑把所有的可能情况都输入到Map映射中,这样直接读取就可以实现
2.注意有两种特殊情况,一个是十位是零,个位不是零,还一个是十位不是零,个位是零
3.一开始对如何把这些字符串放入map中感到疑惑,其实建立一个string[],然后循环放入即可!
4.如何读取一行的string, —getline(cin, str);
以下为书中代码:
#include <cstdio>
#include <iostream>
#include <string>
#include <map>
using namespace std;
string unitDigit[13]={"tret", "jan", "feb", "mar", "apr", "may",
"jun", "jly", "aug", "sep", "oct", "nov", "dec"};
string tenDigit[13]={"tret", "tam", "hel", "maa", "huh", "tou",
"kes", "hei", "elo", "syy", "lok", "mer", "jou"};
string numToStr[170];
map<string, int> strToNum;
void init() {
for(int i=0; i<13; i++) {
numToStr[i]=unitDigit[i];
strToNum[unitDigit[i]]=i;
numToStr[i*13]=tenDigit[i];
strToNum[tenDigit[i]]=i*13;
}
for(int i=1; i<13; i++) {
for(int j=1; j<13; j++) {
string str=tenDigit[i]+" "+unitDigit[j];
numToStr[i*13+j]=str;
strToNum[str]=i*13+j;
}
}
}
int main() {
init();
int T;
scanf("%d%c", &T);
while(T--) {
string str;
getline(cin, str);
if(str[0]>='0' && str[0]<='9') {
int num=0;
for(int i=0; i<str.length(); i++) {
num =num*10 + str[i]-'0';
}
cout << numToStr[num] << endl;
} else {
cout << strToNum[str] << endl;
}
}
return 0;
}
A 1054
已通过OJ
#include <iostream>
#include <string>
#include <map>
using namespace std;
map<string, int> strtonum;
int main() {
int n, m, total;
cin >> n >> m;
total=n*m;
string temp;
for(int i=0; i<m; i++) {
for(int j=0; j<n; j++) {
cin >> temp;
map<string, int>::iterator it=strtonum.find(temp);
if(it->second==0) {
strtonum[temp]=1;
} else {
strtonum[temp]++;
}
}
}
map<string, int>::iterator it=strtonum.begin();
for(; it!=strtonum.end(); it++) {
if(it->second>total/2) {
cout << it->first << endl;
break;
}
}
return 0;
}
A 1071
总结:1.< cctype >:This header declares a set of functions to classify and transform individual characters.
详细见链接?
居然还有这种好用的库?
几个函数:①isalnum(int a):判断字符c是不是十进制数字或字母
②:isalpha(int a):判断字符是否为字母
3):tolower(int c), toupper(int c)
等等
以下为柳神代码:
//柳神代码, 优美=.=.jpg
#include <iostream>
#include <map>
#include <cctype>
using namespace std;
int main() {
string s, t;
getline(cin, s);
map<string, int> m; //map会自动按字典序排好哒,所以得到结果直接输出!!!
for(int i=0; i<s.length(); i++) {
if(isalnum(s[i])) {
s[i]=tolower(s[i]);
t += s[i];
}
if(!isalnum(s[i]) || i==s.length()-1) {
if(t.length()!=0) m[t]++;
t="";
}
}
int maxn=0;
for(auto it=m.begin(); it!=m.end(); it++) {
if(it->second>maxn) {
t=it->first;
maxn=it->second;
}
}
cout << t << " " << maxn;
return 0;
}
A1022
总结:1.学会使用map<string, set< int > >!!!注意是一对多,所以要建立多个map,
2.字符串的以及map的参数传递速度较慢,所以query函数要使用引用参数!!!!!
3.使用scanf或cin输入书的编号后必须用getchar吸收掉后面的空格
4.关于while(cin>>str):见链接?返回的是cin(cin本身就是操作对象,且非零,起作用的是操作符>>)
以下为书中代码:
#include <iostream>
#include <cstdio>
#include <map>
#include <string>
#include <set>
using namespace std;
map<string, set<int>> mpTitle, mpAuthor, mpKey, mpPub, mpYear;
void query(map<string, set<int>> &mp, string &str) {
if(mp.find(str)==mp.end()) {
printf("Not Found\n");
} else {
for(set<int>::iterator it=mp[str].begin(); it!=mp[str].end(); it++) {
printf("%07d\n", *it);
}
}
}
int main() {
int n, m, id, type;
string title, author, key, pub, year;
scanf("%d", &n);
for(int i=0; i<n; i++) {
scanf("%d", &id);
char c=getchar();
getline(cin, title);
mpTitle[title].insert(id);
getline(cin, author);
mpAuthor[author].insert(id);
while(cin>>key) {
mpKey[key].insert(id);
c=getchar();
if(c=='\n') break;
}
getline(cin, pub);
mpPub[pub].insert(id);
getline(cin, year);
mpYear[year].insert(id);
}
string temp;
scanf("%d", &m);
for(int i=0; i<m; i++) {
scanf("%d: ", &type);
getline(cin, temp);
cout << type << ": " << temp << endl;
if(type==1) query(mpTitle, temp);
else if(type==2) query(mpAuthor, temp);
else if(type==3) query(mpKey, temp);
else if(type==4) query(mpPub, temp);
else query(mpYear, temp);
}
return 0;
}