A 第K大区间

不妨考虑二分答案x,则问题转化成计算有多少个区间满足众数出现的次数>=x。

那么这个问题我们使用滑动窗口,枚举右端点,则左端点肯定单调递增,然后维护一个简单的数组就能资瓷添加元素,删除元素,算集合的众数这几项操作了。

时间复杂度O(NlogN)。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<queue>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
using namespace std;
inline int read() {
int x=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
typedef long long ll;
const int maxn=100010;
int n,A[maxn],c[maxn],cnt[maxn],mx,tmp[maxn];
ll k;
void Add(int x) {
cnt[c[x]]--;c[x]++;cnt[c[x]]++;
mx=max(mx,c[x]);
}
void Dec(int x) {
cnt[c[x]]--;c[x]--;cnt[c[x]]++;
while(!cnt[mx]) mx--;
}
int check(int x) {
ll ans=0,l=1;mx=0;
memset(c,0,sizeof(c));
memset(cnt,0,sizeof(cnt));
cnt[0]=n;
rep(r,1,n) {
Add(A[r]);
while(1) {
Dec(A[l]);
if(mx<x) {Add(A[l]);break;}
l++;
}
if(mx>=x) ans+=l;
}
return ans>=k;
}
int main() {
n=read();k=read();
rep(i,1,n) A[i]=tmp[i]=read();
sort(tmp+1,tmp+n+1);
rep(i,1,n) A[i]=lower_bound(tmp+1,tmp+n+1,A[i])-tmp;
int l=1,r=n+1,mid;
while(l+1<r) if(check(mid=l+r>>1)) l=mid;else r=mid;
printf("%d\n",l);
return 0;
}

B 移数博弈

先将A数组算出来,然后用基数排序从大到小排序,然后依次添加到序列中。

A.....B....x.....C.....D

考虑枚举最小值的位置x,那么符合条件的区间应该是[[A+1,B],[x,C-1]]和[[B+1,x],[C,D-1]]。

我们发现添加操作不方便做,那么我们倒序转化成删除操作,就可以用并查集来维护前驱后驱了。

#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
using namespace std;
const int BufferSize=1<<16;
const int inf=1e9;
char buffer[BufferSize],*head,*tail;
inline char Getchar() {
if(head==tail) {
int l=fread(buffer,1,BufferSize,stdin);
tail=(head=buffer)+l;
}
return *head++;
}
inline int read() {
int x=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
typedef long long ll;
const int maxn=10000010;
const int mod=1000000007;
typedef long long ll;
int n,a,b,p,A[maxn],od[maxn],S[maxn];
int pa1[maxn],pa2[maxn];
int findset(int* pa,int x) {return pa[x]==x?x:pa[x]=findset(pa,pa[x]);}
int main() {
n=read();A[0]=read();a=read();b=read();p=read();
rep(i,1,n) S[A[i]=((ll)A[i-1]*a+b)%p]++;
rep(i,1,p) S[i]+=S[i-1];
dwn(i,n,1) od[S[A[i]]--]=i;
rep(i,1,n) pa1[i]=pa2[i]=i;
pa1[0]=0;pa2[n+1]=n+1;
ll ans=0;
rep(i,1,n) {
int x=od[i],u,v,k;pa1[x]=x-1;pa2[x]=x+1;
u=findset(pa1,x-1);k=findset(pa2,x+1);
if(u) {
v=findset(pa1,u-1);
(ans+=((ll)A[x]*A[u]%mod)*((ll)(u-v)*(k-x)%mod)%mod)%=mod;
}
if(k!=n+1) {
v=findset(pa2,k+1);
(ans+=((ll)A[x]*A[k]%mod)*((ll)(v-k)*(x-u)%mod)%mod)%=mod;
}
}
printf("%lld\n",ans);
return 0;
}

C 逛街

枚举最后停在哪个店前,然后在已经走过的ci=1的店中选bi前k小的店来逛,最后再从剩下的商店中二分选最多的来逛就可以了。

前面的操作可以用个堆,后面的操作可以用棵主席树。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<queue>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
using namespace std;
inline int read() {
int x=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
typedef long long ll;
const int maxn=100010;
const int inf=2e9;
const int maxnode=4000010;
int n,k,A[maxn],B[maxn],C[maxn];
priority_queue<int> Q;
int sz[maxnode],ls[maxnode],rs[maxnode],ToT;
ll sumv[maxnode];
void insert(int& o,int l,int r,int p,int val) {
if(!o) o=++ToT;sz[o]+=val;sumv[o]+=p*val;
if(l==r) return;int mid=l+r>>1;
if(p<=mid) insert(ls[o],l,mid,p,val);
else insert(rs[o],mid+1,r,p,val);
}
int query(int& o,int l,int r,int k) {
if(!o) return 0;
if(l==r) return min(sz[o],k/l);
int mid=l+r>>1;
if(sumv[ls[o]]>k) return query(ls[o],l,mid,k);
return query(rs[o],mid+1,r,k-sumv[ls[o]])+sz[ls[o]];
}
int main() {
n=read();ll T=read();k=read();
rep(i,1,n) A[i]=read();
rep(i,1,n) B[i]=read();
rep(i,1,n) C[i]=read();
ll need=(ll)k*inf;
rep(i,1,k) Q.push(inf);
int ans=0,ok=0,rt=0;
rep(i,1,n) {
if(C[i]==1) {
if(k&&B[i]<Q.top()) {
need-=Q.top()-B[i];
if(Q.top()!=inf) insert(rt,1,1e9,Q.top(),1);
Q.pop();Q.push(B[i]);
}
else insert(rt,1,1e9,B[i],1);
}
else insert(rt,1,1e9,B[i],1);
if(need<=T-A[i]) {
ok=1;int res=k+query(rt,1,1e9,T-A[i]-need);
ans=max(ans,res);
}
}
printf("%d\n",ok?ans:-1);
return 0;
}

D Rikka with Sequences

对于一个询问,如果考虑影响它的操作的话不方便实现。我们选择考虑贡献法:

对于一个操作,去考虑它影响的所有询问。

不难发现询问应该在操作之后而且询问的区间应该包含操作的端点。

那么前者我们时光倒流,后者我们用kd树以左端点为x,右端点为y。这样问题就转化成一个经典的整体增加并维护历史最大值的问题(参考BZOJ3064:CPU监控)。

但是数据卡kd树,那么我们可以定期暴力重构整棵kd树强制让它平衡。

#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define L T[o].l
#define R T[o].r
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
using namespace std;
inline int read() {
int x=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
typedef long long ll;
const int maxn=100010;
const int inf=1e9;
int n,m,D,A[maxn],Tp[maxn],Tl[maxn],Tr[maxn];
ll sumv[maxn];
ll query(int x) {ll res=0;for(;x;x-=x&-x) res+=sumv[x];return res;}
void add(int x,int val) {for(;x<=n;x+=x&-x) sumv[x]+=val;}
struct Node {
int x[2],mn[2],mx[2];
int l,r,id;
ll sumv,add,maxs,maxa;
bool operator < (const Node& ths) const {return x[D]<ths.x[D];}
}T[maxn],B[maxn];
int ToT;
void maintain(int o) {
rep(i,0,1) {
T[o].mn[i]=min(T[o].x[i],min(T[L].mn[i],T[R].mn[i]));
T[o].mx[i]=max(T[o].x[i],max(T[L].mx[i],T[R].mx[i]));
}
}
void Add1(int o,ll v) {
if(!o) return;
T[o].maxs=min(T[o].maxs,T[o].sumv+v);
T[o].maxa=min(T[o].maxa,T[o].add+v);
}
void Add2(int o,ll v) {
if(!o) return;
T[o].maxs=min(T[o].maxs,T[o].sumv+=v);
T[o].maxa=min(T[o].maxa,T[o].add+=v);
}
void pushdown(int o) {
if(T[o].maxa) {
Add1(L,T[o].maxa);Add1(R,T[o].maxa);
T[o].maxa=0;
}
if(T[o].add) {
Add2(L,T[o].add);Add2(R,T[o].add);
T[o].add=0;
}
}
void modify(int o,int x,int val) {
if(!o) return;
pushdown(o);
if(T[o].mx[0]<=x&&T[o].mn[1]>=x) {Add2(o,(ll)val);return;}
if(T[o].x[0]<=x&&T[o].x[1]>=x) T[o].sumv+=val,T[o].maxs=min(T[o].maxs,T[o].sumv);
if(T[L].mn[0]<=x&&T[L].mx[1]>=x) modify(L,x,val);
if(T[R].mn[0]<=x&&T[R].mx[1]>=x) modify(R,x,val);
}
void insert(int& o,int x0,int x1,int id,int c) {
if(!o) {
o=++ToT;T[o].x[0]=x0;T[o].x[1]=x1;
T[o].id=id;T[o].sumv=T[o].maxs=query(x1)-query(x0-1);
}
else {
pushdown(o);
if(!c) {
if(x0<=T[o].x[0]) insert(L,x0,x1,id,c^1);
else insert(R,x0,x1,id,c^1);
}
else {
if(x1<=T[o].x[1]) insert(L,x0,x1,id,c^1);
else insert(R,x0,x1,id,c^1);
}
}
maintain(o);
}
int cnt;
ll ans[maxn];
void dfs(int o) {
if(!o) return;
pushdown(o);
B[++cnt]=T[o];
ans[T[o].id]=T[o].maxs;
dfs(L);dfs(R);
}
void build(int& o,int l,int r,int c) {
o=0;if(l>r) return;
int mid=l+r>>1;D=c;o=mid;
nth_element(B+l,B+mid,B+r+1);
T[o]=B[mid];build(L,l,mid-1,c^1);build(R,mid+1,r,c^1);
maintain(o);
}
int main() {
int rt=0;
T[0].mn[0]=T[0].mn[1]=inf;
T[0].mx[0]=T[0].mx[1]=-inf;
n=read();m=read();
rep(i,1,n) A[i]=read(),add(i,A[i]);
rep(i,1,m) {
Tp[i]=read(),Tl[i]=read(),Tr[i]=read();
if(Tp[i]==1) add(Tl[i],Tr[i]-A[Tl[i]]),Tr[i]=Tr[i]-A[Tl[i]],A[Tl[i]]+=Tr[i];
}
int SIZE=2000;
dwn(i,m,1) {
if(Tp[i]==1) modify(rt,Tl[i],-Tr[i]),add(Tl[i],-Tr[i]);
else insert(rt,Tl[i],Tr[i],i,0);
if(i%SIZE==0) {
cnt=0;dfs(rt);rt=0;
build(rt,1,cnt,0);
}
}
cnt=0;dfs(rt);
rep(i,1,m) if(Tp[i]==2) printf("%lld\n",ans[i]);
return 0;
}

E 小Z的trie

构出Trie树然后再上面建广义后缀自动机,询问时倍增一下答案就是right集的大小。

卡卡内存就过去了。

#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
const int BufferSize=1<<16;
char buffer[BufferSize],*head,*tail;
inline char Getchar() {
if(head==tail) {
int l=fread(buffer,1,BufferSize,stdin);
tail=(head=buffer)+l;
}
return *head++;
}
inline int read() {
int x=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const int maxn=1000010;
const int maxm=100010;
const int maxnode=1800010;
int ch[maxn][26],pos[maxn],pos2[maxn],sz,cur;
void insert(char* s) {
int j=0;
for(int i=0;s[i];i++) {
int c=s[i]-'a';
if(!ch[j][c]) ch[j][c]=++sz;
j=ch[j][c];pos[++cur]=j;
}
}
int fa[maxnode],l[maxnode],s[maxnode],to[maxnode][26],cnt=1;
int extend(int p,int c) {
int np=++cnt,q,nq;l[np]=l[p]+1;s[np]=1;
for(;!to[p][c];p=fa[p]) to[p][c]=np;
if(!p) fa[np]=1;
else {
q=to[p][c];
if(l[p]+1==l[q]) fa[np]=q;
else {
l[nq=++cnt]=l[p]+1;
fa[nq]=fa[q];fa[q]=fa[np]=nq;
memcpy(to[nq],to[q],sizeof(to[q]));
for(;to[p][c]==q;p=fa[p]) to[p][c]=nq;
}
}
return np;
}
struct Node {
int x,p;
}Q[maxnode];
void bfs(int x,int p) {
int l=0,r=0;Q[r++]=(Node){x,p};
while(l<r) {
x=Q[l].x;p=Q[l].p;l++;
rep(c,0,25) if(ch[x][c]) {
int np=extend(p,c);pos2[ch[x][c]]=np;
Q[r++]=(Node){ch[x][c],np};
}
}
}
char str[maxn];
int len[maxm];
int c[maxn],od[maxnode];
int anc[maxnode][22];
int main() {
int n=read();
rep(i,1,n) {
scanf("%s",str);
len[i]=len[i-1]+strlen(str);
insert(str);
}
bfs(0,1);int mx=0;
rep(i,1,cnt) c[l[i]]++,mx=max(mx,l[i]);
rep(i,1,mx) c[i]+=c[i-1];
rep(i,1,cnt) od[c[l[i]]--]=i;
dwn(i,cnt,1) s[fa[od[i]]]+=s[od[i]];
rep(i,1,cnt) {
int x=od[i];
anc[x][0]=fa[x];
rep(i,1,21) anc[x][i]=anc[anc[x][i-1]][i-1];
}
dwn(i,read(),1) {
int t=read(),x=read(),y=read();x+=len[t-1];y+=len[t-1];
int len=y-x+1;y=pos2[pos[y]];
dwn(i,21,0) if(l[anc[y][i]]>=len) y=anc[y][i];
printf("%d\n",s[y]);
}
return 0;
}

  

51nod算法马拉松12的更多相关文章

  1. 51NOD 算法马拉松12

    OTZ做出题目的神犇..断断续续改完了在这里存一下思路吧 A题:第K大区间题意:定义一个区间的值为其众数出现的次数.现给出n个数,求将所有区间的值排序后,第K大的值为多少. 分析:二分答案mid,任务 ...

  2. 51Nod 算法马拉松12 Rikka with sequences

    当时做比赛的时候听说过这类用KD_Tree维护的数据结构题 然后知道是KD_Tree,然而并不知道怎么写QAQ 比赛完了之后%了一发代码 其基本思路是这样的: 1.首先我们把询问[L,R]看成二维平面 ...

  3. 51Nod 算法马拉松12 移数博弈

    点进去发现并不是博弈QAQ 一开始考虑单调队列什么乱七八糟的发现根本做不出来 (没错我一直在想枚举最大值求次大值QAQ 不妨换个思路: 我们考虑枚举次大值求最大值 设当前为now, 设now之前第一个 ...

  4. 51NOD 算法马拉松8

    题目戳这里:51NOD算法马拉松8 某天晚上kpm在玩OSU!之余让我看一下B题...然后我就被坑进了51Nod... A.还是01串 水题..怎么乱写应该都可以.记个前缀和然后枚举就行了.时间复杂度 ...

  5. 51nod 算法马拉松 34 Problem D 区间求和2 (FFT加速卷积)

    题目链接  51nod 算法马拉松 34  Problem D 在这个题中$2$这个质数比较特殊,所以我们先特判$2$的情况,然后仅考虑大于等于$3$的奇数即可. 首先考虑任意一个点对$(i, j)$ ...

  6. 随便玩玩系列之一:SPOJ-RNG+51nod 算法马拉松17F+51nod 1034 骨牌覆盖v3

    先说说前面的SPOJ-RNG吧,题意就是给n个数,x1,x2,...,xn 每次可以生成[-x1,x1]范围的浮点数,把n次这种操作生成的数之和加起来,为s,求s在[A,B]内的概率 连续形的概率 假 ...

  7. 51Nod 算法马拉松21(迎新年)

    这次打算法马拉松是在星期五的晚上,发挥还算正常(废话,剩下的题都不会= =). 讲讲比赛经过吧. 8:00准时发题,拿到之后第一时间开始读. A配对,看上去像是二分图最大权匹配,一看范围吓傻了,先跳过 ...

  8. 51Nod 算法马拉松15 记一次悲壮而又开心的骗分比赛

    OwO 故事的起源大概是zcg前天发现51Nod晚上有场马拉松,然后他就很开心的过去打了 神奇的故事就开始了: 晚上的时候我当时貌似正在写线段树?然后看见zcg一脸激动告诉我第一题有九个点直接输出B就 ...

  9. 51Nod 算法马拉松23 开黑记

    惨啊……虽然开了半天黑,但是还是被dalao们踩了…… 第二次开黑,还是被卡在rank20了,我好菜啊……= = 写一写比赛经过吧…… 看到题之后习惯性都打开,A~D看上去似乎并没有什么思路,F应该是 ...

随机推荐

  1. C# 一些常用的技巧代码

    1.字符串风格成字符数组: 比如将字符串:23$123$45$转换成int[]这样的数组,你该怎么转换?其实你不用写那么的for循环,只需要一句话: int [] Relst =Array.Conve ...

  2. SQL语法中的子查询Subqueries

    记一下样子. 明白它的应用场景. SELECT account_id, product_cd, cust_id, avail_balance FROM account WHERE open_emp_i ...

  3. Power BI for Office 365介绍

    微软在七月份发布了一个新产品,它建立在微软的云的第一个数据平台- Power BI for Office 365.Satya Nadella,服务器和工具业务总裁,在当天的上午在微软的年度全球合作伙伴 ...

  4. GMap.Net开发之在地图上添加多边形

    上一篇介绍了在GMap上添加自定义标签(GMapMarker),这篇介绍在GMap上添加多边形(GMapPolyogn),并且介绍如何在地图上画任意的多边形. 如果已经知道了多边形的各个点的位置,就可 ...

  5. JS获取form表单的所有输入值

    function getFormQueryString(frmID) { var frmID=document.getElementById(frmID); var i,queryString = & ...

  6. [Linux] 安装JDK和Maven及hadoop相关环境

    紧接上一篇,继续安装hadoop相关环境 JDK安装:     1. 下载,下面这两个地址在网上找的,可以直接下载:         http://download.oracle.com/otn-pu ...

  7. MySQL5.7更改密码时出现ERROR 1054 (42S22): Unknown column 'password' in 'field list'

    转自:http://blog.csdn.net/u010603691/article/details/50379282 新安装的MySQL5.7,登录时提示密码错误,安装的时候并没有更改密码,后来通过 ...

  8. C专家编程cdecl

    理解所有分析过程的代码段 Page71(中文版) 你可以轻松地编写一个能够分析C语言的声明并把他们翻译成通俗语言的程序.事实上,为什么不?C语言声明的基本形式已经描述清楚.我们所需要的只是编写一段能够 ...

  9. [Unity3d插件]EasyTouch的初步使用

    对于移动平台上的RPG类的游戏,我们常用虚拟摇杆来控制人物角色的行走和一些行为,相信我们对它并不陌生,之前尝试了EasyTouch2.5,发现并没有最新版的3.1好用,2.5版本的对于自适应没有做的很 ...

  10. 如何设计一个优秀的API(转)

    到目前为止,已经负责API接近两年了,这两年中发现现有的API存在的问题越来越多,但很多API一旦发布后就不再能修改了,即时升级和维护是必须的.一旦API发生变化,就可能对相关的调用者带来巨大的代价, ...