zoukankan      html  css  js  c++  java
  • 【CF633H】Fibonacci-ish II 莫队+线段树

    【CF633H】Fibonacci-ish II

    题意:给你一个长度为n的序列$a_i$。m个询问,每个询问形如l,r:将[l,r]中的所有$a_i$排序并去重,设得到的新数列为$b_i$,求$b_1F_1+b_2F_2+...$($F_i$是斐波那契数)。

    $n,mle 30000,a_ile 10^9$

    题解:比较好想,但细节很难处理的题(我根本不懂斐波那契数列~)。

    显然只能用莫队。我们对权值开一棵线段树,那么新加入一个数时,我们要进行的是:单点修改,区间整体换成下一个斐波那契数。如果你懒的话直接上矩乘就完事了,如果你还想知道矩阵的每一项到底是什么数的话,自己手推递推式就好了。区间整体换成上一个斐波那契数呢?手动求个逆就行了。

    #include <cstring>
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #define lson x<<1
    #define rson x<<1|1
    using namespace std;
    const int maxn=30010;
    int n,m,N,Q,B;
    int f[maxn],g[maxn],p[maxn],ref[maxn],cnt[maxn],v[maxn],ans[maxn];
    struct node
    {
    	int l,r,org;
    }q[maxn];
    int s[maxn<<2][2],siz[maxn<<2],tag[maxn<<2];
    bool cmp2(const node &a,const node &b)
    {
    	return (a.l/B==b.l/B)?(a.r<b.r):(a.l/B<b.l/B);
    }
    bool cmp1(const int &a,const int &b)
    {
    	return v[a]<v[b];
    }
    inline void upd(int x,int y)
    {
    	tag[x]+=y;
    	if(y>0)
    	{
    		int a=s[x][0],b=s[x][1];
    		s[x][0]=(f[y+1]*a+f[y]*b)%m,s[x][1]=(f[y]*a+f[y-1]*b)%m;
    	}
    	else
    	{
    		int a=s[x][0],b=s[x][1];
    		y=-y;
    		s[x][0]=(g[y-1]*a+g[y]*b)%m,s[x][1]=(g[y]*a+g[y+1]*b)%m;
    	}
    }
    void updata(int l,int r,int x,int a,int b,int y)
    {
    	siz[x]+=y;
    	if(l==r)
    	{
    		if(y==-1)	s[x][0]=s[x][1]=0;
    		else	s[x][0]=f[b]*ref[l]%m,s[x][1]=f[b-1]*ref[l]%m;
    		return ;
    	}
    	if(tag[x])	upd(lson,tag[x]),upd(rson,tag[x]),tag[x]=0;
    	int mid=(l+r)>>1;
    	if(a<=mid)	updata(l,mid,lson,a,b,y),upd(rson,y);
    	else	updata(mid+1,r,rson,a,b+siz[lson],y);
    	s[x][0]=(s[lson][0]+s[rson][0])%m,s[x][1]=(s[lson][1]+s[rson][1])%m;
    }
    inline void add(int x)
    {
    	if(!cnt[x])	updata(1,N,1,x,1,1);
    	cnt[x]++;
    }
    inline void del(int x)
    {
    	cnt[x]--;
    	if(!cnt[x])	updata(1,N,1,x,0,-1);
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	n=rd(),m=rd(),B=500;
    	int i,l,r;
    	for(i=1;i<=n;i++)	v[i]=rd(),p[i]=i;
    	sort(p+1,p+n+1,cmp1);
    	for(i=1;i<=n;i++)
    	{
    		if(i==1||v[p[i]]!=ref[N])	ref[++N]=v[p[i]];
    		v[p[i]]=N;
    	}
    	for(i=1;i<=N;i++)	ref[i]%=m;	
    	f[1]=1,g[1]=1;
    	for(i=2;i<=n+1;i++)	f[i]=(f[i-1]+f[i-2])%m,g[i]=(g[i-2]-g[i-1])%m;
    	Q=rd();
    	for(i=1;i<=Q;i++)	q[i].l=rd(),q[i].r=rd(),q[i].org=i;
    	sort(q+1,q+Q+1,cmp2);
    	for(l=1,r=0,i=1;i<=Q;i++)
    	{
    		while(l>q[i].l)	add(v[--l]);
    		while(l<q[i].l)	del(v[l++]);
    		while(r<q[i].r)	add(v[++r]);
    		while(r>q[i].r)	del(v[r--]);
    		ans[q[i].org]=(s[1][0]+m)%m;
    	}
    	for(i=1;i<=Q;i++)	printf("%d
    ",ans[i]);
    	return 0;
    }//3 1000 1 2 3 3 1 1 3 3 1 3
  • 相关阅读:
    新的思考方式
    我在干售后!
    设计制造嵌入式系统
    镶嵌在系统中的系统
    苏黄永郦的第六周读书报告
    苏黄永郦的第五周读书报告
    苏黄永郦的第四周读书报告
    苏黄永郦的第三周读书报告
    1051 最大子矩阵和
    1065 最小正子段和
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8594754.html
Copyright © 2011-2022 走看看