zoukankan      html  css  js  c++  java
  • 51nod算法马拉松12

    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
    ",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
    ",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
    ",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
    ",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
    ",s[y]);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    简单了解一下:var 、let、const
    C# FlagAttriute 的 小妙招
    项目经验面试题
    linux面试题详解
    jvm面试题详解
    数据库面试详解
    微服务框架面试题
    框架面试题(maven、ZooKeeper、Dubbo、Nginx、Redis、Lucene、Solr、ActiveMQ、JMS
    设计模式面试题详解
    WEB方面面试题详解
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5328668.html
Copyright © 2011-2022 走看看