zoukankan      html  css  js  c++  java
  • 【洛谷5072】[Ynoi2015] 盼君勿忘(莫队)

    点此看题面

    大致题意: 一个序列,每次询问一个区间([l,r])并给出一个模数(p),求模(p)意义下区间([l,r])内所有子序列去重后值的和。

    题意转化

    原来的题意看起来似乎很棘手,因此需要一定的转化。

    考虑一个值(x)的贡献,设它在区间中出现的次数为(cnt_x),则共有(2^{r-l+1}-2^{r-l+1-cnt_x})个子序列中有这个值,因此它的贡献就是(xcdot (2^{r-l+1}-2^{r-l+1-cnt_x}))

    经这么一转化,不难发现,要求出这个式子的值,我们需要高效维护出区间内每个数的出现次数。

    怎么维护呢?结合题目来源是Ynoi,我们不难想到莫队

    计算答案

    通过莫队,我们能够在(O(nsqrt n))的时间内轻松求出(cnt_x)

    但必须要注意此题最大的坑点,因为模数是由询问给出的,所以我们无法直接维护答案中(2)的幂。

    那么,我们就需要考虑,如何在维护(cnt_x)的基础上,对于每个询问,在(O(sqrt n))的时间内快速计算出答案。

    研究(xcdot (2^{r-l+1}-2^{r-l+1-cnt_x}))这个式子,可以发现在(cnt)相等时,后面(2)的幂是相同的,因此我们可以想到设(sum_i=sum_{cnt_x=i} x),则答案就是(sum sum_icdot(2^{r-l+1}-2^{r-l+1-i}))

    (sum_i)可以在维护(cnt_x)的时候一同维护,但如果我们求答案时真的去枚举(i),复杂度依然是(O(n))

    所以我们可以考虑设阈值:

    • 对于(cnt_xlesqrt n),我们直接枚举这(sqrt n)(sum_i)计算答案,单次询问复杂度为(O(sqrt n))
    • 对于(cnt_x>sqrt n),由于(sum cnt_x=r-l+1le n),因此这样的(x)不超过(sqrt n)个,可以在莫队同时用链表维护,然后询问时扫描链表计算答案,单次询问复杂度为(O(sqrt n))

    这样一来复杂度就做到了(O(nsqrt n))

    预处理(2)的幂——真正的(O(nsqrt n))

    注意,如果用快速幂来求(2)的幂,显然,会让复杂度多带一个(log),这就让原本已经较高的复杂度更是难以接受,因此需要想办法去掉这个(log)

    怎样才能做到呢?很简单,其实预处理一下就可以了。

    由于模数是询问中给出的,所以我们需要对于每个询问(O(sqrt n))预处理出(2)的幂。

    实际上,我们只需预处理(p2_i=2^i,p1_i=2^{isqrt n}),然后就能实现(O(sqrt n))预处理、(O(1))计算了。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    using namespace std;
    int n,Bs,Qt,a[N+5];
    struct Query
    {
    	int l,r,X,p,bl;I Query(CI x=0,CI y=0,CI g=0,CI i=0):l(x),r(y),X(g),p(i){Bs&&(bl=(x-1)/Bs+1);}
    	I bool operator < (Con Query& o) Con {return bl^o.bl?bl<o.bl:(bl&1?r<o.r:r>o.r);}
    }q[N+5];
    I int Qpow(RI x,RI y,RI X) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define pc(c) (C==E&&(clear(),0),*C++=c)
    		#define tn (x<<3)+(x<<1)
    		#define D isdigit(c=tc())
    		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
    	public:
    		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
    		Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
    		Tp I void writeln(Con Ty& x) {write(x),pc('
    ');}
    		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
    }F;
    class MoQueueSolver
    {
    	private:
    		#define P(x) (1LL*p1[(x)/Bs]*p2[(x)%Bs]%X)//计算2的幂
    		#define Ins(x) (nxt[x]=lnk,lst[lnk]=x,lnk=x)//链表中插入
    		#define Kill(x) ((x)^lnk?(lst[nxt[x]]=lst[x],nxt[lst[x]]=nxt[x]):(lnk=nxt[x]))//链表中删除
    		#define Add(x) cnt[x]==Bs&&Ins(x),cnt[x]<=Bs&&(sum[cnt[x]]-=x),++cnt[x]<=Bs&&(sum[cnt[x]]+=x)//加入元素
    		#define Del(x) cnt[x]==Bs+1&&Kill(x),cnt[x]<=Bs&&(sum[cnt[x]]-=x),--cnt[x]<=Bs&&(sum[cnt[x]]+=x)//删除元素
    		int X,ans[N+5],p1[N+5],p2[N+5],cnt[N+5],lnk,lst[N+5],nxt[N+5];long long sum[N+5];
    		I int Qry(CI l,CI r)//询问答案
    		{
    			RI i,p=P(r-l+1),t=0;for(i=1;i<=Bs;++i) t=(1LL*(p-P(r-l+1-i)+X)*(sum[i]%X)+t)%X;//对于小于等于sqrt(n)的部分
    			for(i=lnk;i;i=nxt[i]) t=(1LL*i*(p-P(r-l+1-cnt[i])+X)+t)%X;return t;//对于大于sqrt(n)的部分
    		}
    	public:
    		I void Solve()
    		{
    			RI i,j,L=1,R=0;for(sort(q+1,q+Qt+1),i=1;i<=Qt;++i)//莫队
    			{
    				W(R<q[i].r) ++R,Add(a[R]);W(L>q[i].l) --L,Add(a[L]);
    				W(R>q[i].r) Del(a[R]),--R;W(L<q[i].l) Del(a[L]),++L;
    				for(X=q[i].X,p1[0]=p2[0]=j=1;j<=Bs;++j) p2[j]=(p2[j-1]<<1)%X;//预处理2的幂
    				for(j=1;j<=(q[i].r-q[i].l+1)/Bs;++j) p1[j]=1LL*p1[j-1]*p2[Bs]%X;
    				ans[q[i].p]=Qry(q[i].l,q[i].r);//求解并记下答案
    			}
    			for(i=1;i<=Qt;++i) F.writeln(ans[i]);//输出答案
    		}
    }M;
    int main()
    {
    	RI i,x,y,z;for(F.read(n),F.read(Qt),Bs=sqrt(n),i=1;i<=n;++i) F.read(a[i]);
    	for(i=1;i<=Qt;++i) F.read(x),F.read(y),F.read(z),q[i]=Query(x,y,z,i);//读入并存储询问
    	return M.Solve(),F.clear(),0;
    }
    
  • 相关阅读:
    算法-转
    单页 SEO-转
    浅谈MVVM设计模式
    iOS-UIView动画
    iOS 核心动画(下)
    iOS开发-核心动画(Core Animation)
    iOS-CALayer的介绍
    SVN Xcode不能提交.a文件
    iOS 毛玻璃效果
    Quartz2D学习总结
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu5072.html
Copyright © 2011-2022 走看看