做了一个NOI上面的问题,叫blah集合,以a为基数,则2x+1和3x+1都在集合中,且集合中全部元素都由此计算得来。a∈[1,50],问升序排列后第n(n∈[1,1000000])个元素是多少。以输入示例a=1,n=100,b[n]=418为例:
集合中第一个元素(基数)为1,
1 3 4 7 10 9 2x+1: 3 7 9 15 21 19…… 3x+1: 4 10 13 22 31 27……
依次计算时会发现每1个数据会变为2个,这些数又会发生交叉。题目需要得到升序后第n个,我们如果先计算再排序一定会超时的,所以我们需要分别把2x+1和3x+1存储起来,然后取之前存储的较小的输出出来,队列很适合这项工作:
#include<iostream> #include<queue> typedef unsigned long long uint64; using namespace std; uint64 blah(int base,int maxid){ int curval=base,curid=1; queue<uint64> x2,x3; x2.push(curval*2+1); x3.push(curval*3+1); while(maxid!=curid){ if(x2.front()==x3.front()){ curval=x2.front(); x2.pop(); x3.pop(); }else if(x2.front()<x3.front()){ curval=x2.front(); x2.pop(); }else{ curval=x3.front(); x3.pop(); } x2.push(curval*2+1); x3.push(curval*3+1); curid++; } return curval; } int main(){ int base,maxid; while(true){ cin>>base>>maxid; cout<<blah(base,maxid)<<endl; } }
不过遗憾的是,这份代码超时了,虽然它在我的计算机上计算得到结果是瞬间的事情。那么问题在哪呢?只能说可能出现在对front和pop的调用耗时上,当然也可能有内存分配方面的耗时。好吧,我们避免这些调用和重复的初始化——用数组来模拟一下队列:
#include<iostream> typedef unsigned long long uint64; using namespace std; uint64 x2[1000000],x3[1000000]; uint64 blah(int base,int maxid){ int curval=base,curid=1,x2id=0,x3id=0,x2cnt=0,x3cnt=0,x2val,x3val; x2[x2cnt]=curval*2+1; x3[x3cnt]=curval*3+1; while(maxid!=curid){ x2val=x2[x2id]; x3val=x3[x3id]; if(x2val==x3val){ curval=x2val; x2id++; x3id++; }else if(x2val<x3val){ curval=x2val; x2id++; }else{ curval=x3val; x3id++; } x2[++x2cnt]=curval*2+1; x3[++x3cnt]=curval*3+1; curid++; } return curval; } int main(){ int base,maxid; while(scanf("%d %d",&base,&maxid)!=EOF){ printf("%llu\n",blah(base,maxid)); } }
这份代码就以很短的时间通过了测试。