luogu P5338 [TJOI2019]甲苯先生的滚榜

传送门

首先,排名系统,一看就知道是原题,可以上平衡树来维护

然后考虑一种比较朴素的想法,因为我们要知道排名在一个人前面的人数,也就是AC数比他多的人数+AC数一样并且罚时少的人数,所以考虑维护那两个东西.AC数更多的人数显然可以直接上树状数组.后者的话可以对每一种AC数开值域线段树,存每个罚时有多少人,注意到罚时之和不会超过\(1.5*10^6\),所以动态开点线段树可以轻松解决.然后每次有个人AC数和罚时改变就先在原来的位置-1,然后在新位置+1.每次询问就是树状数组上AC数\(>\)当前AC数的对应区间之和\(+\)对应线段树上罚时\(<\)当前罚时的区间之和

// luogu-judger-enable-o2
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<ctime>
#include<queue>
#include<map>
#include<set>
#define LL long long
#define ui unsigned int

using namespace std;
const int N=1e5+10,M=1e6+10,MX=1500000;
LL rd()
{
    LL x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
ui randNum(ui& seed ,ui last,const ui m)
{
    seed=seed*17+last;
    return seed%m+1;
}
ui sd;
int m,n,a[N],b[N],c[M];
void ad(int x,int y){while(x<=n) c[x]+=y,x+=x&(-x);}
int gsm(int x){int an=0;while(x) an+=c[x],x-=x&(-x);return an;}
int s[M*25],ch[M*25][2],rt[M],tt;
void add(int o1,int o2,int x)
{
    int l=1,r=MX;
    s[o1]=s[o2]+1;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(x<=mid)
        {
            ch[o1][0]=++tt,ch[o1][1]=ch[o2][1];
            o1=ch[o1][0],o2=ch[o2][0];
            r=mid;
        }
        else
        {
            ch[o1][0]=ch[o2][0],ch[o1][1]=++tt;
            o1=ch[o1][1],o2=ch[o2][1];
            l=mid+1;
        }
        s[o1]=s[o2]+1;
    }
}
void dec(int o,int x)
{
    int l=1,r=MX;
    --s[o];
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(x<=mid) o=ch[o][0],r=mid;
        else o=ch[o][1],l=mid+1;
        --s[o];
    }
}
int quer(int o,int l,int r,int ll,int rr)
{
    if(ll>rr||!o) return 0;
    if(ll<=l&&r<=rr) return s[o];
    int an=0,mid=(l+r)>>1;
    if(ll<=mid) an+=quer(ch[o][0],l,mid,ll,rr);
    if(rr>mid) an+=quer(ch[o][1],mid+1,r,ll,rr);
    return an;
}

int main()
{
    int T=rd(),ans=7;
    while(T--)
    {
        m=rd(),n=rd(),sd=rd();
        for(int i=1;i<=n;++i) c[i]=rt[i]=0;
        for(int i=1;i<=m;++i) a[i]=b[i]=0;
        tt=0;
        for(int i=1;i<=n;++i)
        {
            int x=randNum(sd,ans,m),y=randNum(sd,ans,m);
            if(a[x]) dec(rt[a[x]],b[x]),ad(a[x],-1);
            ++a[x],b[x]+=y;
            int las=rt[a[x]];
            add(rt[a[x]]=++tt,las,b[x]),ad(a[x],1);
            ans=gsm(n)-gsm(a[x])+quer(rt[a[x]],1,MX,1,b[x]-1);
            printf("%d\n",ans);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/smyjr/p/10841151.html

时间: 2024-08-30 17:09:45

luogu P5338 [TJOI2019]甲苯先生的滚榜的相关文章

「TJOI2019」甲苯先生的滚榜

题目链接 问题分析 参照数据范围,我们需要一个能够在\(O(n\log n)\)复杂度内维护有序数列的数据结构.那么平衡树是很好的选择.参考程序中使用带旋Treap. 参考程序 #pragma GCC optimize( 3 ) #include <cstdio> #include <ctime> #include <algorithm> namespace Treap { struct member { int Number, Time; bool operator

【题解】Luogu P5342 [TJOI2019]甲苯先生的线段树

原题传送门 挺有趣的一道题 \(c=1\),暴力求出点权和n即可 \(c=2\),先像\(c=1\)一样暴力求出点权和n,考虑有多少路径点权和也为n 考虑设x为路径的转折点,\(L\)为\(x\)向左儿子走的长度,\(R\)为\(x\)向右儿子走的长度.易知当\(L,R\)确定时,有唯一的\(x\)对应 以\(x\)为转折点,\(L,R\)为向左/右儿子走的距离,这时点权和至少为\(Min=(2^{L+1}+2^{R+1}-3)x+2^R-1\) 此时x的取值一定珂以求出.考虑一下如何产生剩下\

【题解】Luogu P5337 [TJOI2019]甲苯先生的字符串

原题传送门 我们设计一个\(26*26\)的矩阵\(A\)表示\(a~z\)和\(a~z\)是否能够相邻,这个矩阵珂以由\(s1\)得出.答案显然是矩阵\(A^{len_{s2}-1}\)的所有元素之和,矩阵快速幂即可 #include <bits/stdc++.h> #define ll long long #define mod 1000000007 using namespace std; inline void write(register int x) { if(!x)putchar

[TJOI2019]甲苯先生和大中锋的字符串

有个叫asuldb的神仙来嘲讽我 说这题SAM水题,而且SA过不了 然后我就用SA过了 显然是一个Height数组上长为k的滑块,判一下两边,差分一下就可以了 #include"cstdio" #include"cstring" #include"iostream" #include"algorithm" using namespace std; const int MAXN=1e5+5; int n,T,mx,hd,tl;

【题解】Luogu P5339 [TJOI2019]唱、跳、rap和篮球

原题传送门 这题zsy写的是\(O(n^2)\),还有NTT\(O(n^2\log n)\)的做法.我的是暴力,\(O(\frac{a b n}{4})\),足够通过 考虑设\(f(i)\)表示序列中至少有\(i\)组人讨论cxk的方案数 这样就珂以进行容斥,易知答案ans为: \[ans=\sum_{i=0}^{Min(n/4,a,b,c,d)} (-1)^i f(i)\] 我们考虑如何计算\(f(i)\) 如果视讨论cxk的组为一个元素,则一共有\(n-3*i\)个元素 我们把问题转换成一个

【题解】Luogu P5340 [TJOI2019]大中锋的游乐场

原题传送门 没想到省选也会出这种题??! 实际就是一个带有限制的最短路 因为\(k<=10\),所以我们珂以暴力将每个点的权值分为[-k,k],为了方便我们珂以转化成[0,2k],将汉堡的权值记为1,可乐的权值记为-1,最短路即可,如果发现不合理的就果断扔掉即可(不知道有没有好事之徒用SPFA写) #include <bits/stdc++.h> #define N 10005 #define pi pair<int,int> #define getchar nc using

p5341 [TJOI2019]甲苯先生和大中锋的字符串

分析 TJOI白给题 建出sam,对于每个点如果它的子树siz和等于k 那么对于这个满足的点它有贡献的长度一定是一个连续区间 直接差分即可 代码 #include<bits/stdc++.h> using namespace std; int n,k,mx,ans,d[100100]; char s[100100]; struct SAM { int mp[200100][30],fa[200100],ed,ccnt,len[200100],siz[200100]; int head[2001

Luogu P5339 [TJOI2019]唱、跳、rap和篮球

题目 设\(f_i\)表示从\((a-4i,b-4i,c-4i,d-4i)\)中选\(n-4i\)个排队的方案数. 那么我们可以容斥,答案为\(\sum\limits_{i=0}^{lim}(-1)^i{n-3i\choose i}f_i\). 考虑一下这个\(f\),它就是四个指数型生成函数卷起来\((\sum\limits_{i=0}^a\frac{x^i}{i!})(\sum\limits_{i=0}^b\frac{x^i}{i!})(\sum\limits_{i=0}^c\frac{x^

ACM退役记&amp;&amp;回忆录

ACM退役记 2017.9.19星期二,"九一八事变"八十六年后的第二天,永远记住这个日子,刚好是我报名ACM到现在,刚好满一年,而今天正是我注册杭州电子科技大学OJ的时间(就是这一天报名的),附上小图一张! 嗯,我退役了,真的退役了,从此告别了ACM的生涯,虽然有很多遗憾,虽然有很多不舍,虽然有很多很多不情愿,但是,,,还是没能阻止这一天的到来,可能你们会认为我退役的有点早,可能你们也会有很多疑惑,为啥这么优秀这么强的大佬竟然退役的这么早...(自嘲一下,其实菜的一逼) 其实这个原因