bzoj 2161: 布娃娃

Description

小时候的雨荨非常听话,是父母眼中的好孩子。在学校是老师的左右手,同学的好榜样。后来她成为艾利斯顿第二
代考神,这和小时候培养的良好素质是分不开的。雨荨的妈妈也为有这么一个懂事的女儿感到高兴。一次期末考试
,雨荨不知道第多少次,再次考了全年级第一名。雨荨的妈妈看到女儿100分的成绩单时,脸上又泛起了幸福的笑
容,作为奖励,她给雨荨买了n个布娃娃。细心的雨荨发现,第i个布娃娃有一个耐心值P[i]以及一个魅力值C[i],
并且还有能够忍受的耐心值的上限R[i]以及下限L[i]。当一个布娃娃j满足L[j]<=P[i]并且P[i]<=R[j],那么布娃
娃j喜欢布娃娃i。雨荨还发现,一个布娃娃有可能喜欢它自己。每个布娃娃心中都有一个谜团,具体来说就是:第
i个布娃娃想知道喜欢它的布娃娃中,魅力值第i大的布娃娃的魅力值是多少,并且称这个布娃娃的谜团答案为这个
魅力值的大小,如果不存在,那么这个布娃娃的谜团答案为0。鉴于雨荨的上司栋栋不让题目的数据过大,下面给
出数据的生成方法:给出16个参数:

Padd, Pfirst, Pmod, Pprod, Cadd, Cfirst, Cmod, Cprod, Ladd, Lfirst, Lmod, Lprod, Radd, Rfirst, Rmod, Rprod。

P[1] = Pfirst % Pmod, P[i] = (P[i-1] Pprod + Padd + i) % Pmod (i > 1)。

对于C、L、R数组也有类似的得到方式, %代表取余运算。注意:L和R数组生成完之后,如果某个布娃娃的忍耐度上
限小于下限,那么交换它的上限和下限。当然,雨荨也不会让你告诉她每个布娃娃的谜团答案,因为那样会使输出
数据很大。所以雨荨希望你告诉她,所有布娃娃谜团答案的和除以19921228的余数是多少。
Input

输入的第一行有一个整数n,代表布娃娃的个数。
输入的第二行有16个用空格隔开的整数
分别代表Padd,Pfirst,Pmod,Pprod,Cadd,Cfirst,Cmod,Cprod,Ladd,Lfirst,Lmod,Lprod,Radd,Rfirst,Rmod,Rprod。
16个参数均为1到100,000,000中的整数。
Output

输出一个整数,代表所有布娃娃谜团答案的和除以19921228的余数。

Sample Input

3

2 3 4 3 1 4 5 2 3 6 9 1 1 2 3 4
Sample Output

4

题解

一开始想的是一个 nlog2n 的做法
但是我现在已经忘了QAQ。。
因为我后来想了一个更好的,就把它抛弃了。。
首先这题显然是可以离散化的吗。。
L,R,P一起离
C自己离(其实C离不离都可以)
我们就将P排序
然后我们就用一条L,R,P的线扫过去。。
到达一个L的时候就+1,到达一个R的时候就-1
然后到达一个新的P就在线段树上二分一下就好了
具体看代码
感觉挺简单的,应该看得懂
CODE:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long LL;
const LL MAX=1<<28;
const LL N=100005*10;
const LL MOD=19921228;
LL n;
LL P[N],C[N],L[N],R[N];
void print()
{
    for (LL u=1;u<=n;u++)
        printf("L:%lld R:%lld P:%lld C:%lld\n",L[u],R[u],P[u],C[u]);
    printf("\n");
}
void Read()
{
    scanf("%lld",&n);
    LL Padd,Pfirst,Pmod,Pprod,Cadd,Cfirst,Cmod,Cprod,Ladd,Lfirst,Lmod,Lprod,Radd,Rfirst,Rmod,Rprod;
    scanf("%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld",&Padd,&Pfirst,&Pmod,&Pprod,&Cadd,&Cfirst,&Cmod,&Cprod,&Ladd,&Lfirst,&Lmod,&Lprod,&Radd,&Rfirst,&Rmod,&Rprod);   
    P[1]=Pfirst%Pmod;
    for (LL i=2;i<=n;i++) P[i]=(P[i-1]*Pprod+Padd+i)%Pmod;
    C[1]=Cfirst%Cmod;
    for (LL i=2;i<=n;i++) C[i]=(C[i-1]*Cprod+Cadd+i)%Cmod;
    L[1]=Lfirst%Lmod;
    for (LL i=2;i<=n;i++) L[i]=(L[i-1]*Lprod+Ladd+i)%Lmod;
    R[1]=Rfirst%Rmod;
    for (LL i=2;i<=n;i++) R[i]=(R[i-1]*Rprod+Radd+i)%Rmod;
    for(LL i=1;i<=n;i++) if(L[i]>R[i])swap(L[i],R[i]);

}
LL a[N],cnt;//这个数组是属于c的,表示这个位置其实是多少 
LL A[N],Cnt;//这个是离散化专用
LL find (LL x)
{
    LL l=1,r=Cnt;
    while (l<=r)
    {
        LL mid=(l+r)>>1;
        if (A[mid]==x) return mid;
        else if (A[mid]>x) r=mid-1;
        else l=mid+1;
    }
}
void prepare ()//预处理 大概就是离散化一下 
{
//  print();
    cnt=0;
    for (LL u=1;u<=n;u++)
        a[++cnt]=C[u];
    sort(a+1,a+1+cnt);LL cntt=cnt;cnt=1;
    for (LL u=2;u<=cntt;u++)
        if (a[u]!=a[cnt])
            a[++cnt]=a[u];
    for (LL u=1;u<=n;u++)
    {
        LL l=1,r=cnt;
        while (l<=r)
        {
            LL mid=(l+r)>>1;
            if (a[mid]==C[u])   {C[u]=mid;break;}
            else if (a[mid]>C[u]) r=mid-1;
            else l=mid+1;
        }
    }

    Cnt=0;
    for (LL u=1;u<=n;u++)   A[++Cnt]=P[u],A[++Cnt]=L[u],A[++Cnt]=R[u];
    sort(A+1,A+1+Cnt);cntt=Cnt;Cnt=1;
    for (LL u=2;u<=cntt;u++)
        if (A[u]!=A[Cnt])
            A[++Cnt]=A[u];
    for (LL u=1;u<=n;u++) L[u]=find(L[u]),R[u]=find(R[u]),P[u]=find(P[u]);

//  print();
}
struct qt
{
    LL x,y,z,last;
}e[N];LL num,last[N];
void init (LL x,LL y,LL z)
{
    num++;
    e[num].x=x;e[num].y=y;e[num].z=z;
    e[num].last=last[x];
    last[x]=num;
}
struct qy
{
    LL l,r;
    LL s1,s2;
    LL c;//这一段有多少 
}s[N];
void bt (LL l,LL r)
{
    LL a=++num;
    s[a].l=l;s[a].r=r;
    s[a].c=0;
    if (l==r) return ;
    LL mid=(l+r)>>1;
    s[a].s1=num+1;bt(l,mid);
    s[a].s2=num+1;bt(mid+1,r);
}
void change (LL now,LL x,LL z)
{
    s[now].c+=z;
    if (s[now].l==s[now].r) return ;
    LL mid=(s[now].l+s[now].r)>>1;
    LL s1=s[now].s1,s2=s[now].s2;
    if (x<=mid) change(s1,x,z);
    else change(s2,x,z);
}
struct ql
{
    LL id,p;
}shen[N];
bool cmp (ql a,ql b){return a.p<b.p;}
LL get (LL now,LL x)
{
    if (s[now].l==s[now].r) return s[now].l;
    LL s1=s[now].s1,s2=s[now].s2;
    if (s[s2].c>=x) return get(s2,x);
    else return get(s1,x-s[s2].c);
}
void solve ()
{
/*  print();
    printf("%lld\n",cnt);
    for (LL u=1;u<=cnt;u++) printf("%lld ",a[u]);
    printf("\n");*/
    num=0;memset(last,-1,sizeof(last));
    for (LL u=1;u<=n;u++){init(L[u],C[u],1);init(R[u]+1,C[u],-1);}
    num=0;bt(0,cnt);
    change(1,0,MAX);

    for (LL u=1;u<=n;u++) shen[u]={u,P[u]};
    sort(shen+1,shen+1+n,cmp);

    shen[0].p=0;
    LL ans=0;
    for (LL u=1;u<=n;u++)
    {
        for (LL i=shen[u-1].p+1;i<=shen[u].p;i++)//吧这些都加上
            for (LL j=last[i];j!=-1;j=e[j].last)
            {
                change(1,e[j].y,e[j].z);
            //  printf("YES:%lld %lld\n",e[j].y,e[j].z);
            }
    //  printf("%lld %lld %lld\n",shen[u].p,shen[u].id,get(1,shen[u].id));
        ans=ans+a[get(1,shen[u].id)];
        ans%=MOD;
    }
    printf("%lld\n",ans);
}
int main()
{
    Read();
    prepare();
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值