HDU 6040 Hints of sd0061(nth_element)

来源:互联网 发布:淘宝增值服务是什么 编辑:程序博客网 时间:2024/06/06 15:42

Description
给出一个长度为n的序列a[i],以及m次查询b[1],…,b[m],第i次查询a序列中第b[i]+1大的数
Input
多组用例,每组用例首先输入五个整数n,m,A,B,C,n表示序列长度,m表示查询数,A,B,C经过下列操作逐一生成a序列
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;
}
之后输入m个整数b[i]表示查询,b序列满足b[i]+b[j] < b[k],其中b[i]!=b[j],b[i],b[j] < b[k],以文件尾结束输入(1<=n<=1e7,1<=m<=100,0<=b[i] < n)
Output
对于每组用例,输出m个整数表示这m次操作的答案
Sample Input
3 3 1 1 1
0 1 2
2 2 2 2 2
1 1
Sample Output
Case #1: 1 1 202755
Case #2: 405510 405510
Solution
nth_element在O(n)时间内就可以找到一个长度为n的序列中第k大的数,但是此题O(mn)的复杂度也是不能接受的,注意到b序列排好序去重之后满足斐波那契性质,故每次序列长度会缩短很多,当b是斐波那契数列时每次会序列会变为原来的1/1.618,故不同的b最多只有这里写图片描述个,每次更新一下查询区间的上限即可
时间复杂度为这里写图片描述
Code

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<vector>#include<queue>#include<map>#include<set>#include<ctime>using namespace std;typedef long long ll;const int maxn=10000001;int n,m;unsigned A,B,C,a[maxn],ans[101];struct node{    int val,id;    bool operator<(const node&b)const    {        return val>b.val;    }}b[101];unsigned x,y,z;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 res=1;    while(~scanf("%d%d%u%u%u",&n,&m,&A,&B,&C))    {        x=A,y=B,z=C;        for(int i=0;i<m;i++)        {            scanf("%d",&b[i].val);            b[i].id=i;        }        sort(b,b+m);        for(int i=0;i<n;i++)a[i]=rng61();        int pos=n;        for(int i=0;i<m;i++)        {            nth_element(a,a+b[i].val,a+pos);            ans[b[i].id]=a[b[i].val];            pos=b[i].val;        }        printf("Case #%d: ",res++);        for(int i=0;i<m;i++)printf("%u%c",ans[i],i==m-1?'\n':' ');    }    return 0;}
原创粉丝点击