170 likes | 314 Views
7.2,7.6结题报告 --陈静. 7.2 排名系统. 题目描述 : osu!是一款ytaaa最喜欢的音乐游戏,但是最近ytaaa的排名一直没有上升,所以ytaaa打算研究一下osu的排名系统。 osu!的排名是以pp来排序的,pp越高排名越靠前。现在ytaaa弄到了osu的排名数据,出于见不得人的目的,ytaaa想知道pp值为k的用户的资料,但是即使弄到了数据,查询也需要耗费大量的时间,所以ytaaa希望你能帮助他写一段代码来快速的给出ytaaa想要的信息。. 7.2 排名系统. 解题思路: 1.根据pp值是按从高到低排好序
E N D
7.2 排名系统 题目描述: osu!是一款ytaaa最喜欢的音乐游戏,但是最近ytaaa的排名一直没有上升,所以ytaaa打算研究一下osu的排名系统。 osu!的排名是以pp来排序的,pp越高排名越靠前。现在ytaaa弄到了osu的排名数据,出于见不得人的目的,ytaaa想知道pp值为k的用户的资料,但是即使弄到了数据,查询也需要耗费大量的时间,所以ytaaa希望你能帮助他写一段代码来快速的给出ytaaa想要的信息。
7.2 排名系统 解题思路: 1.根据pp值是按从高到低排好序 2.我们要找pp为k的数据的位置,就可以输出对应的资料 3.由于数据很大,1<=n<=100000,1<=m<=10000,枚举的复杂度是O(m*n),会超时,所以我们需要用二分法,复杂度是O(m*log(2)n)。
7.2 排名系统 解题思路: 二分法上次课已经讲过,这里不再赘述 二分法主要代码 int bidsch(int k){ int l=0,r=n-1; if(a[l].pp==k)return l; if(a[r].pp==k)return r; int mid; for(;;){ mid=(l+r)/2; if(a[mid].pp==k)return mid; else if(a[mid].pp>k)l=mid; else r=mid;}}
7.2 排名系统 主要代码: struct data{ char s[15]; int pp; }a[100005]; int n; int cmp(data x,data y){ return x.pp>y.pp;} int main(){ scanf("%d",&n); int i; for(i=0;i<n;i++) scanf("%s%d",a[i].s,&a[i].pp); sort(a,a+n,cmp);//快排排序 int m; scanf("%d",&m); while(m--){ int k; scanf("%d",&k); printf("%s\n",a[bidsch(k)].s); } return 0;}
7.6 永真判断 题目描述: 这道题的目的是判断一串逻辑表达式是否为永真式(即不论逻辑变量如何取值,其结果永远为真)。为了减小计算难度,这串式子中只会出现a,b,c,d,e,5个逻辑变量(体贴的老师)。共涉及4个操作,分别是K,A,N,E。Kab指a&&b,Aab指a||b,Na指!a,E指a==b(相等取真),例如EKAabNaEcd(E(K(Aab)(Na))(Ecd))是一个合法的表达串,AaNa为永真式,因为不论a的取值是真是假,AaNa恒为真,而AaNb就不是一个永真式。为了增加难度,一个合法串的长度可能到达100。
7.6 永真判断 首先了解一个前序表达式的概念 前序表达式就是不含括号的算术表达式,而且它是将运算符写在前面,操作数写在后面的表达式,也称为“波兰式”。例如,- 1 + 2 3,它等价于1-(2+3)。 题目的表达式其实也可以看做前序表达式,只是它的运算是逻辑运算而不是算术运算
7.6 永真判断 解题思路: 所以这是一个对前序表达式的运算问题 对于一个前序表达式的求值而言,首先要从右至左扫描表达式,从右边第一个字符开始判断,如果当前字符是数字则一直到数字串的末尾再记录下来,如果是运算符,则将右边离得最近的两个“数字串”作相应的运算,以此作为一个新的“数字串”并记录下来。一直扫描到表达式的最左端时,最后运算的值也就是表达式的值。。
7.6 永真判断 解题思路: 对于一个前序表达式的求值而言,首先要从右至左扫描表达式,从右边第一个字符开始判断,如果当前字符是数字则一直到数字串的末尾再记录下来,如果是运算符,则根据运算符的的运算变量的个数将右边离得最近的一个或两个“数字串”作相应的运算,以此作为一个新的“数字串”并记录下来。一直扫描到表达式的最左端时,最后运算的值也就是表达式的值。
7.6 永真判断 解题思路: 例如,前序表达式“- 1 + 2 3“的求值,扫描到3时,记录下这个数字串,扫描到2时,记录下这个数字串,当扫描到+时,将+右移做相邻两数字串的运算符,记为2+3,结果为5,记录下这个新数字串,并继续向左扫描,扫描到1时,记录下这个数字串,扫描到-时,将-右移做相邻两数字串的运算符,记为1-5,结果为-4,所以表达式的值为-4。
7.6 永真判断 解题思路: 如果你理解了上面的运算,那么对于这题的运算你应该也明白了! 那我们就举个这题的例子EKAabNaEcd我们知道它的运算过程是(E(K(Aab)(Na))(Ecd)) 同理根据上面的方法,先从右开始扫描,碰到a,b,c,d,e的就跳过,直到遇到运算符即K,A,N,E
7.6 永真判断 解题思路: 所以先运算Ecd,然后把运算后的结果s1可以存到新的数组里面,继续扫描,遇到 N,那么就运算Na,同时保存结果s2,再运算Aab,结果为s3,继续像左扫描,遇到K,此时拿紧邻的右边的2个数s2,s3来运算,得到s4,最后是遇到E,此时再判断s4和s1是否相等,最后得到s5,此时扫描结束,那么s5就是最后的答案
7.6 永真判断 解题思路: 还有一个问题是a,b,c,d,e的值不确定,所以共有2的5次方即32种可能,所以我们每一种情况都要判断表达式的 真假,如果32种情况下,表达式都为真,那么就是永真式
7.6 永真判断 解题思路: 前面的解法可以有很多实现方法,可以用栈 参考代码是用函数递归的方式实现的
7.6 永真判断 示例代码: #include<stdio.h> har a[10000]; int k; int f[10]; bool judge(void){//递归函数 k++; if(a[k]=='K')return judge()&judge(); if(a[k]=='A')return judge()|judge(); if(a[k]=='N')return !judge(); if(a[k]=='E')return judge()==judge(); return f[a[k]-'a']; }
7.6 永真判断 示例代码: int main(){ scanf("%s",a); bool mark=true; for(f[0]=0;f[0]<=1;f[0]++) for(f[1]=0;f[1]<=1;f[1]++) for(f[2]=0;f[2]<=1;f[2]++) for(f[3]=0;f[3]<=1;f[3]++) for(f[4]=0;f[4]<=1;f[4]++){ k=-1; if(!judge())mark=false; } if(mark)printf("Yes\n");//全都为真 else printf("No\n"); return 0; }