中位数的和_KEY

来源:互联网 发布:hp3055扫描仪驱动软件 编辑:程序博客网 时间:2024/06/05 07:21

中位数的和

(number.pas/c/cpp)

【题目描述】

flower 有 N-1 个朋友,他们要一起玩一个游戏:首先确定三个非负整数 a,b,c,然后每个人依次在纸上写一个数,设第 i 个人写下的数字为 f[i],flower 先写下数字 f[1]=1,对于第 i 个写数字的人(i>1)有: f[i]=(a*m[i-1]+b*i+c)mod1,000,000,007;其中 m[i-1]为前 i-1 个写下的数字的中位数,如果 i-1 为偶数,那么取靠前的那个数。flower 想要知道,所有人写下的数字的和。

【输入格式】

输入仅一行,包含四个非负整数 a,b,c,N;意义如上;

【输出格式】

输出只有一行一个整数,表示数字和。

【输入样例】

3 1 2 6

【输出样例】

103

【数据规模】

对于 30%的数据: N≤1,000;

对于 100%的数据: N≤200,000; a,b,c≤1,000,000,007。

第一次拿到这道题,给我的感觉是F[1~i-1]一定比F[i]小,所以中位数一定是F[i>>1](CJJDs也是这样想的),但马上被我否认了,因为我注意到有一个mod,所以值可能会变小。于是立马换一种思路,既然叫我们求中位数,即中间的数,那么我们将已存的有序数列掰成两半,中间的即为中位数。那么这里就需要用到一个大根堆,用于存储前半段数,一个小根堆,用于存储后半段数。每次将生成的数放入小根堆,如果当前是第i次操作且i为奇数,那么将小根堆顶放入大根堆。注意mod后如果小于大根堆顶就交换。

code

#include <cstdio>#include <cctype>#include <queue>#define mod 1000000007#define C c = tc ( )using namespace std;inline char tc(){    static char fl[100000],*A,*B;    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;}inline void read(long long &x){    static char c;    while(!isdigit(C));x=c-'0';    while(isdigit(C))x=x*10+c-'0';}long long a,b,c,n;long long f[200001];priority_queue<long long>w1;priority_queue<long long,vector<long long>,greater<long long> >w2;int main(){    freopen("number.in","r",stdin);    freopen("number.out","w",stdout);    read(a),read(b),read(c),read(n);    w1.push(f[1]=1);        for(int i=2;i<=n;i++){            long long val=w1.top(),ve;            f[i]=(val*a+b*i+c)%mod;ve=f[i];            if(ve<val)w1.pop(),w1.push(ve),ve=val;            w2.push(ve);            if(i&1)val=w2.top(),w2.pop(),w1.push(val);        }    long long ans=0;        for(int i=1;i<=n;i++)ans+=f[i];    printf("%lld",ans);    fclose(stdin),fclose(stdout);    return 0;}

最后引用CJJ的话。

如果是Pascal的话我也可以,用Pascal打堆!

原创粉丝点击