1
老师想知道从某某同学当中,分数最高的是多少,现在请你编程模拟老师的询问。当然,老师有时候需要更新某位同学的成绩.
思路:
①区间最大值,点更新。
这里是最简单的,其实还有区间求和,区间最大值,区间最小值,点更新,区间更新。
可以用线段树、树状数组、RMQ
①这里只简单说明一下区间最大值和点更新,剩余的放在下一个篇详细介绍。
②就用线段树吧,n个数据,就是n个叶子节点存放数据。父节点表示范围的最大值,每次修改之后需要向上更新。
③如何建树?
线段树,build(1,1,n)递归建树,当节点的l==r的时候,递归结束,叶子节点(这里的l和r不是左右子树而是左右覆盖范围),依次得到的叶子节点肯定是从左到右的(8-->9-->5-->6-->7)。l和r可以表示输入数据的下标,就是覆盖范围嘛。更新点的值比更新区间的值要简单,查到点只需要向上更新即可。
代码:
#include<stdio.h>
#define N 30005
struct node{
int l; //节点左覆盖范围
int r; //节点右覆盖范围
int value; //覆盖范围的最大值
}p[N*2];
int a[N]; //输入数据
int max(int a,int b){
return a>b?a:b;
}
void build(int o,int l,int r){
p[o].l=l;
p[o].r=r;
if(l==r) { //叶子节点
p[o].value=a[l];
return;
}
int mid=(l+r)/2;
build(o*2,l,mid);
build(o*2+1,mid+1,r);
p[o].value=max(p[o*2].value,p[o*2+1].value);
}
//从根节点开始查
int Find(int o,int l,int r){
if(p[o].l==l&&p[o].r==r){
return p[o].value;
}
//左儿子的右覆盖范围 小于 l (在右子树)
if(l>p[o*2].r) return Find(o*2+1,l,r);
//右儿子的左覆盖范围 大于 r (在左子树)
else if(r<p[o*2+1].l) return Find(o*2,l,r);
//横跨左右子树
else return max(Find(o*2,l,p[o*2].r),Find(o*2+1,p[o*2+1].l,r));
}
//更新点的值,需要向上更新父亲节的值
void update(int o,int index,int x){
if(p[o].l==p[o].r){ //查找,当l==r时,index==r==l
p[o].value=x;
return; //一定要要结束递归
}
if(index<=p[o*2].r) update(o*2,index,x);
else update(o*2+1,index,x);
p[o].value=max(p[o*2].value,p[o*2+1].value);
}
int main(){
int n,m,x1,x2;
char str[5];
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n);
while(m--){
scanf("%s%d%d",str,&x1,&x2);
if(str[0]=='Q'){
if(x1>x2){
int xx=x1;
x1=x2;
x2=xx;
}
printf("%d\n",Find(1,x1,x2));
}else{
update(1,x1,x2);
}
}
}
return 0;
}
2
开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号。
处理:
1.记录最多8条错误记录,对相同的错误记录(即文件名称和行号完全匹配)只记录一条,错误计数增加;(文件所在的目录不同,文件名和行号相同也要合并)
2.超过16个字符的文件名称,只记录文件的最后有效16个字符;(如果文件名不同,而只是文件名的后16个字符和行号相同,也不要合并)
3.输入的文件可能带路径,记录文件名称不能带路径
思路
①首先字符串处理,有一个转义符误区,得到文件名和行数。然后定义一个map就行相同文件名和行数进行统计,map插入会改变输入顺序,这是第二个误区,需要一个辅助记录输入顺序。最后map转化结构题数组,进行结构体排序。
②结构体排序可以用sort和qsort,但是在本案例中qsort不能通过,我也不知什么个情况,注意cmp函数的返回会值(二者不同),已及决定升降序排序(刚好相反)。
③第一次提交答案错误,给出输出是中间是空格,其实不是,就是一个一行(坑了好久)。
代码
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<stdlib.h>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
using namespace std;
map<string,int> flag;
int counts=0;
struct node{
string x;
int y;
};
//qsort,返回值1和-1代表真假
/*int cmp(const void *a,const void *b){
if((*(struct node *)a).y==(*(struct node *)b).y){
return flag[(*(struct node *)a).x]>flag[(*(struct node *)b).x];
}
return (*(struct node *)a).y > (*(struct node *)b).y ? -1 : 1;
}*/
//sort返回值1和0代表真假
int cmp(const node &a,const node &b){
if(a.y==b.y) return flag[a.x]<flag[b.x]?1:0;
return a.y>b.y?1:0;
}
//并且sort和qsort刚好是相反的
//sort 真是由大到小,qsort假是由大到小
int main(){
char a[1000];
char b[100];
set<string> s; //先添加进来,用于计数
map<string,int> ans;
while(scanf("%s%s",a,b)!=EOF){
int len=strlen(a);
int i=len-1;
for(;i>=0;i--)
if(a[i]=='\\') break; //多加一个反斜杠转义符
string save; //文件名_行数
for(i++;i<len;i++){
save+=a[i];
}
save+=" ";
save+=b;
if(s.find(save)!=s.end()){
ans[save]=ans[save]+1;
}else{ //首次插入
//map插入会乱序,需要一个辅助flag,记录输入顺序
flag[save]=counts++;
s.insert(save);
ans[save]=1;
}
}
struct node p[counts];
int j=0;
map<string,int>::iterator it;
for(it=ans.begin();it!=ans.end();it++){
p[j].x=it->first;
p[j++].y=it->second;
}
sort(p,p+counts,cmp); // qsort(p, counts, sizeof(p[0]),cmp);
int num=0;
for(int i=0;i<counts;i++){
//统计文件名是否超16
int len=(p[i].x).length();
int l;
for(l=len-1;l>=0;l--){
if((p[i].x)[l]==' ') break;
}
if(l<=16) {
cout<<p[i].x;
}else{
string q;
for(int ll=l-16;ll<len;ll++)
q+=(p[i].x)[ll];
cout<<q;
}
cout<<" "<<p[i].y<<endl;
num++;
if(num==8) break;
}
return 0;
}
3
扑克牌游戏大家应该都比较熟悉了,一副牌由54张组成,含3~A,2各4张,小王1张,大王1张。牌面从小到大用如下字符和字符串表示(其中,小写joker表示小王,大写JOKER表示大王):)
3 4 5 6 7 8 9 10 J Q K A 2 joker JOKER
输入两手牌,两手牌之间用“-”连接,每手牌的每张牌以空格分隔,“-”两边没有空格,如:4 4 4 4-joker JOKER
请比较两手牌大小,输出较大的牌,如果不存在比较关系则输出ERROR
基本规则:
(1)输入每手牌可能是个子,对子,顺子(连续5张),三个,炸弹(四个)和对王中的一种,不存在其他情况,由输入保证两手牌都是合法的,顺子已经从小到大排列;
(2)除了炸弹和对王可以和所有牌比较之外,其他类型的牌只能跟相同类型的存在比较关系(如,对子跟对子比较,三个跟三个比较),不考虑拆牌情况(如:将对子拆分成个子)
(3)大小规则跟大家平时了解的常见规则相同,个子,对子,三个比较牌面大小;顺子比较最小牌大小;炸弹大于前面所有的牌,炸弹之间比较牌面大小;对王是最大的牌;
(4)输入的两手牌不会出现相等的情况。
答案提示:
(1)除了炸弹和对王之外,其他必须同类型比较。
(2)输入已经保证合法性,不用检查输入是否是合法的牌。
(3)输入的顺子已经经过从小到大排序,因此不用再排序了.
思路
①首先明确告诉你,出的牌必须合法,单个,对子,顺子,三个,炸弹
②以上五种情况进行排列组合,要么有一方赢,要么组合错误(如单个--对子)
③一种情况是牌数相同,只需要比较第一位即可(不会相等,顺子排好序了)
在一副牌中,都为1的时候是单个,都为2的时候是对子,都为三的时候是三个,都为4的时候是炸弹,都大于等于5的时候是顺子。
④一种情况是牌数不等,一方是炸弹(两种类型,王砸和其它炸),要不然是ERROR。
注意:比如长度是4,那么一定是炸弹(只有炸弹才一次出4张),比如长度是2,要么是对子,要么是王炸。
代码
public class Main {
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
String str=cin.nextLine();
String[] Array=str.split("-");
String[] A=Array[0].split(" ");
String[] B=Array[1].split(" ");
int[] AA=new int[A.length];
int[] BB=new int[B.length];
for(int i=0;i<A.length;i++) {
//3 4 5 6 7 8 9 10 J Q K A 2 joker JOKER
if(A[i].equals("3")) {
AA[i]=3;
}else if(A[i].equals("4")) {
AA[i]=4;
}else if(A[i].equals("5")) {
AA[i]=5;
}else if(A[i].equals("6")) {
AA[i]=6;
}else if(A[i].equals("7")) {
AA[i]=7;
}else if(A[i].equals("8")) {
AA[i]=8;
}else if(A[i].equals("9")) {
AA[i]=9;
}else if(A[i].equals("10")) {
AA[i]=10;
}else if(A[i].equals("J")) {
AA[i]=11;
}else if(A[i].equals("Q")) {
AA[i]=12;
}else if(A[i].equals("K")) {
AA[i]=13;
}else if(A[i].equals("A")) {
AA[i]=14;
}else if(A[i].equals("2")) {
AA[i]=15;
}else if(A[i].equals("joker")) {
AA[i]=16;
}else if(A[i].equals("JOKER")) {
AA[i]=17;
}
}
for(int i=0;i<B.length;i++) {
//3 4 5 6 7 8 9 10 J Q K A 2 joker JOKER
if(B[i].equals("3")) {
BB[i]=3;
}else if(B[i].equals("4")) {
BB[i]=4;
}else if(B[i].equals("5")) {
BB[i]=5;
}else if(B[i].equals("6")) {
BB[i]=6;
}else if(B[i].equals("7")) {
BB[i]=7;
}else if(B[i].equals("8")) {
BB[i]=8;
}else if(B[i].equals("9")) {
BB[i]=9;
}else if(B[i].equals("10")) {
BB[i]=10;
}else if(B[i].equals("J")) {
BB[i]=11;
}else if(B[i].equals("Q")) {
BB[i]=12;
}else if(B[i].equals("K")) {
BB[i]=13;
}else if(B[i].equals("A")) {
BB[i]=14;
}else if(B[i].equals("2")) {
BB[i]=15;
}else if(B[i].equals("joker")) {
BB[i]=16;
}else if(B[i].equals("JOKER")) {
BB[i]=17;
}
}
if(A.length!=B.length) {//不等
//一个其它的和一个炸弹
//一个炸弹和一个王炸
if(A.length==2&&AA[0]==16) {
System.out.println(Array[0]);
}else if(B.length==2&&BB[0]==16) {
System.out.println(Array[1]);
}else if(A.length==4) {
System.out.println(Array[0]);
}else if(A.length==4) {
System.out.println(Array[1]);
}else {
System.out.println("ERROR");
}
}else { //相等
if(AA[0]>(BB[0])) {
System.out.println(Array[0]);
}else {
System.out.println(Array[1]);
}
}
}
}