题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=6040
【题意】给定一个生成函数,利用该生成函数生成n个数。给出生成函数的初值A,B,C一个大小为m的B数组,求解第bi+1小的数是什么。B数组满足条件:如果b_i < b_k and b_j < b_k and b_i != b_j,那么b_i+b_j < b_k。
【分析】比赛期间一直很迷B数组的限制条件,赛后看了题解才恍然大悟。由于B数组限制的存在,当与n取最大1000w时,B数组去重后最多不会超过40个,具体个数查看斐波契那函数,同时B数组去重后的数字和在2n左右,具体数额和证明可以自行推理。如此就可以利用类型快排的方法进行求解,具体为现对B数据进行排序,从最大的数开始求解,如此求b_i时就可以只使用1-b_(i-1)了,详细可以参考代码理解。
【代码】
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; #define Uint unsigned int struct Node{ int v,idx; Uint ans; }b[110]; Uint nob[10001000]; Uint A,B,C; bool cmp(Node n1,Node n2){ return n1.v>n2.v; } bool cmp2(Node n1,Node n2){ return n1.idx<n2.idx; } unsigned x = A, y = B, z = C; unsigned rng61() { unsigned t; x ^= x << 16; x ^= x >> 5; x ^= x << 1; t = x; x = y; y = z; z = t ^ x ^ y; return z; } int main(){ int n,m,cas=1; while(~scanf("%d %d %u %u %u",&n,&m,&A,&B,&C)){ for(int i=0;i<m;++i){ scanf("%d",&b[i].v); b[i].idx=i; } sort(b,b+m,cmp); x=A;y=B;z=C; for(int i=0;i<n;++i) nob[i]=rng61(); nth_element(nob,nob+b[0].v,nob+n); b[0].ans=nob[b[0].v]; for(int i=1;i<m;++i){ if(b[i].v==b[i-1].v){ b[i].ans=b[i-1].ans; continue; } nth_element(nob,nob+b[i].v,nob+b[i-1].v); b[i].ans=nob[b[i].v]; } sort(b,b+m,cmp2); printf("Case #%d:",cas++); for(int i=0;i<m;++i) printf(" %u",b[i].ans); cout<<endl; } }