题目连接: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;
}
}