知名的OJ有:RQNOJ,URAL,SPOJ,vijos,USACO,sgu,pku(poj),zju(toj),tju,uva等。
著名OJ网址:
中文OJ:
任青网络在线测评系统RQNOJ:>
树状数组是一个可以很高效的进行区间统计的数据结构。在思想上类似于线段树,比线段树节省空间,编程复杂度比线段树低,但适用范围比线段树小。
以简单的求和为例。设原数组为a[1N],树状数组为c[1N],其中c[k] = a[k-(2^t)+1] + + a[k]。比如c[6] = a[5] + a[6]。也就是说,把k表示成二进制110000,那么c[k]就是100001 + 100010 + + 110000这一段数的和。设一个函数lowestbit(k)为取得k的最低非零位,容易发现,根据上面的表示方法,从a[1]到a[k]的所有数的总和即为sum[k] = c[k] + c[k-lowestbit(k)] + c[k-lowestbit(k)-lowestbit(k-lowestbit(k))] + 于是可以在logk的时间内求出sum[k]。当数组中某元素发生变化时,需要改动的c值是c[k],c[k+lowestbit(k)], c[k+lowestbit(k)+lowestbit(k+lowestbit(k))] 这个复杂度是logN (N为最大范围)
扩展到多维情况:以二维为例,用c[k1][k2]表示c[k1-(2^t1)+1][k2-(2^t2)+1] + + c[k1][k2]的总和。可以用类似的方法进行处理。复杂度为(logn)^k (k为维数)
树状数组相比线段树的优势:空间复杂度略低,编程复杂度低,容易扩展到多维情况。劣势:适用范围小,对可以进行的运算也有限制,比如每次要查询的是一个区间的最小值,似乎就没有很好的解决办法。
多维情况的几道题目:
URAL 1470 UFOs
POJ 2155 Matrix
表面上看,这题的要求似乎和树状数组的使用方法恰好相反,改变的是一个区间,查询的反而是一个点。实际上可以通过一个转化巧妙的解决。
首先对于每个数A定义集合up(A)表示{A, A+lowestbit(A), A+lowestbit(A)+lowestbit(A+lowestbit(A))} 定义集合down(A)表示{A, A-lowestbit(A), A-lowestbit(A)-lowestbit(A-lowestbit(A)) , 0}。可以发现对于任何A<B,up(A)和down(B)的交集有且仅有一个数。
于是对于这道题目来说,翻转一个区间[A,B](为了便于讨论先把原问题降为一维的情况),我们可以把down(B)的所有元素的翻转次数+1,再把down(A-1)的所有元素的翻转次数-1。而每次查询一个元素C时,只需要统计up(C)的所有元素的翻转次数之和,即为C实际被翻转的次数。
实际实现时,由于只考虑奇偶,因此无须统计确切的翻转次数。另外,如果翻转up(A)和up(B+1),查询down(C),也是同样的效果。这种方法可以很容易地扩展到二维情况。比起线段树、四分树之类的常规思路,无论编程复杂度还是常数速度上都有很大优势。 #include<cstdio>#include<iostream>#include<cstring>#include<cstdlib>int x,n,t;char ques[5];int tree[1500][1500];using namespace std;int lowbit(int a){ return a&-a;}void change(int x,int y){ for (int i=x;i<=n;i+=lowbit(i)) { for (int j=y;j<=n;j+=lowbit(j)) { tree[i][j]++; } } return;}int getsum(int x,int y){ int ans=0; for (int i=x;i>=1;i-=lowbit(i)) { for (int j=y;j>=1;j-=lowbit(j)) { ans+=tree[i][j]; } } return ans;}int main(){ scanf (%d,&x); for (int i=1;i<=x;i++) { scanf (%d%d\n,&n,&t); memset(tree,0,sizeof(tree)); for (int i=1;i<=t;i++) { scanf (%s,&ques); if (ques[0]=='C') { int x1,x2,y1,y2; scanf (%d%d%d%d,&x1,&y1,&x2,&y2); change(x1,y1); change(x2+1,y1); change(x1,y2+1); change(x2+1,y2+1); } if (ques[0]=='Q') { int x,y; scanf (%d%d,&x,&y); printf (%d\n,getsum(x,y)%2); } } printf (\n); } return 0;}
简称: cf(所以谈论cf的时候经常被误会成TX的那款游戏)
网址: 在后面加个com就可以了
这是一个俄国的算法竞赛网站,由来自萨拉托夫州立大学、由Mike Mirzayanov领导的一个团队创立和维护,是一个举办比赛、做题和交流的平台举办比赛和做题就不说了,“交流”指的是自带blog功能,可以求助/发布题解之类官方语言是俄语和英语,因此可能有些偏僻的题目的题解是用俄语写的,别慌,扔给Google Translate翻成英文,可读性还是很不错的至于英语,cf上Russian English确实有,但并不严重,题目里偶尔会出现很奇怪的表达方式或者不常用的词汇,这时候就借助样例吧,找个人问问也是可以的cf最大的特点是比赛,所以接下来主要的篇幅用于介绍cf传统比赛的规则
在cf,所有的用户根据在以往比赛中的表现被赋予一个Rating并冠以不同的头衔,名字也会以不同的颜色显示,比如Expert是蓝色,Master是,因此我们通常以颜色代指头衔选手们按Rating以1700为界划分为Div1和Div2两类,相应地,cf上的比赛也会指明是Div1还是Div2,抑或同时进行Div1的比赛较难;如果同时进行,Div1的CDE三题会和Div2的ABC三题相同每次比赛结束后Rating都会有相应的变动对于没有参加过比赛的新用户,在比赛后重新计算Rating的时候,他的Rating会被视为1500
在比赛中,选手有2个小时的时间去解决5道题,而解决某题得到的分数由该题当前的分数减去(不成功的提交次数)50,这里,某道题的分数是由比赛开始时的分数随时间线性减少得到的同时,这里的“解决某道题”是指Pretest Passed,即,通过了一次仅含部分测试点的测评,而最终决定是否得到这道题的分数,要看比赛结束后的统一测评(System Test),如果在这时没有通过,就称FST(Failed System Test)在比赛中的提交可以看到在哪个测试点出了什么问题(例如,仅一行WA on pretest 3)
同一个Div的选手将被划分到若干个Room里,每个Room约20位选手;当某道题Pretest Passed之后,可以选择锁定(Lock)该题代码,之后就可以查看同一个Room内其他选手该题的代码(当然了,这也是已经通过pretest的),并试图找出其中的漏洞,自己出一个数据(可以手打,也可以提交数据生成器)让这个代码不能通过,这就是Hack,有时也称Challenge一次成功的Hack可以得到100分,而如果没有成功,将会被扣50分,分别被称为(un)successful hacking attempt
在比赛中,选手可以看到实时的排名(Standing),也可以选择只看加了好友的选手的排名此外,还可以看到某题有多少人通过的信息,这在某些情况下很有用
关于比赛的事情大概就是这么多cf题库的所有题目都是在该平台上举办过的比赛的赛题,尽管WJMZBMR曾经表示由于出题人很杂cf的题目质量参差不齐,但我个人认为还是够可以的,两个小时五道题也确实很能让人得到锻炼和Spoj形成鲜明对比的,cf的机子很快,所以很容易培养出STL依赖症等等不良代码习惯,应当引起足够的注意
在cf上做题的过程当中如果遇到困难,首先可以看数据数据从某种程度上来说是公开的,在提交记录页面可以看到所有你的程序运行过的数据,但是太大的数据也只会显示前几行,因此也不算完全公开cf的测试数据笔数通常会让习惯了10个点的人大吃一惊,一道题动辄80个测试点,甚至有的有200多笔通常来说,前面大概5组是比赛时的Pretest,尽可能的涵盖各种情况,也有放个大数据卡TLE的;其后的数据规模递增,但是最后几组又会很小——这是比赛时Hack的成果Hack成功的数据会被追加到该题的测试数据当中
如果数据不能解决问题,可以试图去找题解题目页面的右下角会标出它所属的比赛的相关文档,通常会有Announcement(赛前和赛中的公告,其中赛中的公告通常是明确题意之类),有些则会有Tutorial,这就是题解,顺带一提cf上另外一个表示题解的词是Editorial一次比赛的题解可能不是官方的,也可能不包含该词比赛全部的题目的,也有可能是用俄语写的(前面提到过了,翻译成英语就好),也有可能有好几篇(这会以Tutorial #1,#2的形式标识)近期的比赛多半都有官方题解,以前的就不好说了这时候需要借助另外一个神器:神犇们的代码cf上所有的代码都是公开的,并且支持按照提交先后(Judging Time),运行时间(Execution Time)和代码长度(Code Length)进行排序不仅仅是帮助做题,这个功能对于了解一道题的各种做法也是有好处的
这个应该很多的,比如牛客网,还有leetcode很多的,多看看百度知道,选C++标签什么的,还有各种论坛应该也有一堆。如果真的想深入学习的话可以下载一些c++的pdf电子书来看看
经典书籍《c++primer》《算法导论》《编译原理》下面是一些网站:
WelcomeToPKUJudgeOnline北京大学的OnlineJudge。POJ上面的题目有点老了,但好处是做的人多,经典算法题多,解题报告也多,适合上手。
2ZOJ:Home浙江大学的OnlineJudge。ZOJ用的不多,但为数不多的几次体验好像都还可以,值得尝试。
3WelcometoHangzhouDianziUniversityOnlineJudge杭州电子科技大学的OJ。杭电OJ在近几年取代了POJ,成为是目前国内最主流的OJ。它的题目丰富,难度梯度合理,广受全国各大高校的青睐。每年也会有大大小小的比赛挂在杭电的OJ上举办,去年的亚洲区网络赛也是在这上面做的。由此可见其在国内广大ACMer心目中的地位。也正因为如此,网上h的解题报告也很多,适合个人进阶训练。
4UVaOnlineJudge西班牙Valladolid大学的OnlineJudge。是最古老也是全世界最知名的OnlineJudge,题库有详细的分类:如世界总决赛题目,刘汝佳的题目等等。题目目类型非常广泛。绝大部分的题目难度偏易,适合初学者磨练程序设计。
5TimusOnlineJudgeURAL是一个俄罗斯的在线题库。里面的题目相比国内一些OJ来说颇有些难度,我们学校集训队老队员喜欢拿这里的题出给新队员做,可见有一定的进阶作用。
6SphereOnlineJudge(SPOJ)SPOJ是波兰最为出色的OnlineJudge之一,界面和谐,题目类型也非常丰富,适合有一定基础的选手练习,对高手而言也是个提高能力的良好平台。更多介绍见博客:SPOJ简介-海山。
7USAComputingOlympiadUSACO是美国中学生的官方竞赛网站、美国著名在线题库,专门为信息学竞赛选手准备;做题方式模拟正式比赛,采用标准测评机、文件输入输出、直接提交程序源文件的测评方式;网站的Training题目全面,是学习信息学不可不知的网站,每年NOI,NOIP都会参考上面的题目;每道题附有详细题解,可查看测试数据和运行结果,便于调试、发现错误并改正。采用章节递进的层次结构,由易到难,讲授知识、练习编程结合,题目必须依次完成,避免了只挑简单题做的行为;各章节犹如一本竞赛辅导书,形成了一个鲜明的知识结构,利于OI初学者和高手逐步提高水平,充分学习信息学各方面知识,避免偏颇。(来源:usaco_百度百科)
9CodeforcesCodefores是俄罗斯的一个算法竞赛网站,由SaratovStateUniversity创办和维护。Codeforces主要强调的是算法竞赛,每隔1个礼拜左右就会有定期的线上比赛举行,其题库也是由每场比赛的题目一场场积累下来的。相比上面几个以题库为核心的OJ,Codeforces的算法竞赛比较适合锻炼自己的临场发挥和压力下编程能力。
10HUSTOJ华中科技大学的OnlineJudge。hustOJ也和主流的其他OJ一样有着丰富的题库。但它主要的用处,是它所提供的这么一个叫做vjudge的东西,全称叫做VirtualJudge。通过vjudge,你可以从各大OJ、包括但不限于上述的所有OJ中直接抽取题目,利用这些题目创建一个属于你自己的比赛。非常适合专题训练、日常集训以及小伙伴们一起比赛切题玩。
11LeetCodeOnlineJudge与很多OJ不同,leetcode是一个主要面向面试者的OJ(LeetCodeOJisaplatformforpreparingtechnicalcodinginterviews)。上面的题目不多,目前只有152道,很多都是许多大公司的面试题目。题目类型偏基础,基本不会考察复杂的算法,很多都是对基础知识的应用,难度与topcoderdiv1250或codeforcesdiv1A题难度相当。如果是希望练习编程基础或准备公司面试的话非常推荐此OJ(感谢室友/集训队大神/CMU准硕士@yunpeng同学提供Leetcode介绍(1/1/2015更新:室友拿了google的offer不去CMU了))。
希望可以帮到您,谢谢!
Online Judge简称OJ,意思是在线评测平台,多指信息学在线评测平台。 知名的OJ有:URAL,SPOJ,vijos,USACO,sgu,pku(poj),zju(toj),tju,uva等。 著名OJ网址: 北京大学pku: >问题的本质还是要遍历的,只要限制一下遍历规则即可。第一:对于给出的整数n,求起平方根为sqrtn=sqrt(n),查找和为它的两个完全平方数循环到sqrtn(不大于sqrtn的整数);
第二:设两个数分别为a,b;起始遍历条件是:int a=(int)sqrtn;a递减
截至条件是a<b的时候;循环内中给出b的值double b=sqrt(n-aa);
经过这样两步,问题可以简单许多。比如判断122=121+1=十一的平方+1的平方的时候,sqrtn=11=a;b=1;//完成判断。
a=10;b=根号下22(判断它不是整数后 4点几)舍去;
a=9;b=41的平方根6几。舍去。
a=8;b=58的平方根;七点几;舍去;
a=7;显然b>a;停止。
实例:
void dec(int num)
{double sqrtn=sqrt(num),temp;
for(int a=(int(sqrtn),b=0;a>=b;a--)
{ temp=sqrt(num-aa);b=(int)temp;
if((temp-double(b)<=000001)
cout<<a<<","<<b<<"的平方和为;"<<num<<endl;
}
cout<<"查找完毕"<<endl;
}
以上代码编译通过。速度不 错哦。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)