• Codeforces633H-Fibonacci-ish II


    题目

    斐波那契数列(f)(f\_1=f\_2=1, f\_n=f\_{n-1}+f\_{n-2} (n>2))
    给定长度为(n (nle 30000))的数列(a)(q)次询问,每次将(a)的区间([l,r])排序去重,设得到(k)个数:

    [egin{align} ans=sum _{i=1}^k f_ia_i end{align} ]

    分析

    会写莫队啦!会写莫队啦!会写莫队啦!
    莫队算法的排序以左端点所在块和右端点的大小为关键字。
    询问区间,(nle 30000)),可以离线,莫队解决。关键在于如何添加或删除一个数。我们列出式子之后发现,每次操作其实可以等价于两个操作:

    • 添加或删除一个数
    • 把一段区间的数的所有(f)向前或向后移
      这里的排序去重令我们想到可以用权值线段树处理一个数前面有多少个数,所以添加删除可以(O(logn))解决。现在考虑如何处理移动问题。
      我们对于权值线段树的每个点记录两个值,((x,y)),分别表示当前这个点区间内的答案,以及整个区间向后移动一位后的答案。我在这里的做法是用一个标记记录每个区间向右移动的次数(向左为负),然后(pushdown)的时候用矩阵快速幂加一下即可。右移矩阵为:

    [egin{pmatrix} 0 & 1 \ 1 & 1 \ end{pmatrix} ]

    左移矩阵为右移矩阵的逆矩阵,即:

    [egin{pmatrix} -1 & 1 \ 1 & 0 \ end{pmatrix} ]

    时间复杂度:(O(nsqrt n logn))
    这里最重要的思想是用离散化+权值线段树处理排序去重区间操作的问题。

    代码

    函数记得return返回值。
    还有就是每次要把gs清空,也可以用标记实现。

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    typedef long long giant;
    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=3e4+10;
    int n,a[maxn],qn;
    giant q;
    struct ques {
    	int s,t,id;
    	bool operator < (const ques a) const {
    		int sk=s/qn,ak=a.s/qn;
    		return sk==ak?t<a.t:sk<ak;
    	}
    } b[maxn];
    int gs[maxn],tp,tic[maxn<<2],tim=0,tg[maxn];
    giant f[maxn],c[maxn];
    struct node {
    	giant a,b;
    	int mv,g;
    	void clear() {
    		a=b=0,mv=g=0;	
    	}
    } t[maxn<<2];
    struct matrix {
    	giant a[3][3];
    	matrix (int e=0,int f=0,int g=0,int h=0) {
    		a[1][1]=e,a[1][2]=f,a[2][1]=g,a[2][2]=h;
    	}
    	void operator = (matrix x) {
    		for (int i=1;i<=2;++i) for (int j=1;j<=2;++j) a[i][j]=x.a[i][j];
    	}
    } mt,rmt,the;
    matrix operator * (matrix &x,matrix &y) {
    	the=matrix();
    	for (int i=1;i<=2;++i) for (int j=1;j<=2;++j) for (int k=1;k<=2;++k) (the.a[i][j]+=x.a[i][k]*y.a[k][j]+q)%=q;
    	return the;
    }
    matrix mi(int y) {
    	rmt=mt,--y;
    	while (y) {
    		if (y&1) rmt=rmt*mt;
    		y>>=1,mt=mt*mt; // here
    	}
    	return rmt; // here
    }
    void mvit(node &k,int c) {
    	if (c==0) return;
    	int a=k.a,b=k.b;
    	if (c>0) mt=matrix(0,1,1,1); else mt=matrix(-1,1,1,0);
    	c=abs(c);
    	mt=mi(c);
    	k.a=(mt.a[1][1]*a+mt.a[2][1]*b+q)%q,k.b=(mt.a[2][1]*a+mt.a[2][2]*b+q)%q;
    }
    void pushdown(int x) {
    	if (!t[x].mv) return;
    	if (t[x<<1].g) mvit(t[x<<1],t[x].mv),t[x<<1].mv+=t[x].mv;
    	if (t[x<<1|1].g) mvit(t[x<<1|1],t[x].mv),t[x<<1|1].mv+=t[x].mv;
    	t[x].mv=0;
    }
    int qnum(int x,int L,int R,int l,int r) {
    	if (tic[x]!=tim) t[x].clear(),tic[x]=tim;
    	if (l>r) return 0;
    	pushdown(x);
    	if (L==l && R==r) return t[x].g;
    	int mid=(L+R)>>1;
    	if (r<=mid) return qnum(x<<1,L,mid,l,r);
    	if (l>mid) return qnum(x<<1|1,mid+1,R,l,r);
    	return qnum(x<<1,L,mid,l,mid)+qnum(x<<1|1,mid+1,R,mid+1,r);
    }
    void update(int x) {
    	t[x].g=t[x<<1].g+t[x<<1|1].g;
    	t[x].a=(t[x<<1].a+t[x<<1|1].a)%q;
    	t[x].b=(t[x<<1].b+t[x<<1|1].b)%q;
    }
    void add(int x,int l,int r,int p,int wh,int d) {
    	if (tic[x]!=tim) t[x].clear(),tic[x]=tim;
    	pushdown(x);
    	if (l==r) {
    		t[x].g+=d;
    		if (d==1) {
    			t[x].a=(f[wh]*c[p])%q;
    			t[x].b=(f[wh+1]*c[p])%q;
    		} else t[x].a=t[x].b=0;
    		return;
    	}
    	int mid=(l+r)>>1;
    	if (p<=mid) add(x<<1,l,mid,p,wh,d); else add(x<<1|1,mid+1,r,p,wh,d);
    	update(x);
    }
    void moveit(int x,int L,int R,int l,int r,int d) {
    	if (tic[x]!=tim) t[x].clear(),tic[x]=tim;
    	if (l>r) return;
    	pushdown(x);
    	if (L==l && R==r) {
    		t[x].mv+=d;
    		mvit(t[x],d);
    		return;
    	}
    	int mid=(L+R)>>1;
    	if (r<=mid) moveit(x<<1,L,mid,l,r,d); else 
    	if (l>mid) moveit(x<<1|1,mid+1,R,l,r,d); else {
    		moveit(x<<1,L,mid,l,mid,d);
    		moveit(x<<1|1,mid+1,R,mid+1,r,d);
    	}
    	update(x);
    }
    void inc(int x) {
    	if (tg[x]!=tim) tg[x]=tim,gs[x]=0;
    	gs[x]++;
    	if (gs[x]>1) return;
    	int wh=qnum(1,1,tp,1,x-1)+1;
    	add(1,1,tp,x,wh,1);
    	moveit(1,1,tp,x+1,tp,1);
    }
    void dec(int x) {
    	if (tg[x]!=tim) tg[x]=tim,gs[x]=0;
    	gs[x]--;
    	if (gs[x]) return;
    	add(1,1,tp,x,0,-1);
    	moveit(1,1,tp,x+1,tp,-1);
    }
    giant ans[maxn];
    int main() {
    	#ifndef ONLINE_JUDGE
    		freopen("test.in","r",stdin);
    		freopen("my.out","w",stdout);
    	#endif
    	n=read(),q=read();
    	f[1]=f[2]=1;
    	for (int i=3;i<=n+5;++i) f[i]=(f[i-1]+f[i-2])%q;
    	qn=sqrt(n);
    	for (int i=1;i<=n;++i) c[i]=a[i]=read();
    	sort(c+1,c+n+1);
    	tp=unique(c+1,c+n+1)-c-1;
    	for (int i=1;i<=n;++i) a[i]=lower_bound(c+1,c+tp+1,a[i])-c;
    	int m=read();
    	for (int i=1;i<=m;++i) b[i].s=read(),b[i].t=read(),b[i].id=i;
    	sort(b+1,b+m+1);
    	int nk=-1,l,r;
    	for (int i=1;i<=m;++i) {
    		if ((b[i].s-1)/qn>nk) {
    			nk=(b[i].s-1)/qn;
    			++tim;
    			//memset(gs,0,sizeof gs); // here
    			r=b[i].s-1,l=b[i].s;
    		}
    		while (r<b[i].t) inc(a[++r]);
    		while (l>b[i].s) inc(a[--l]);
    		while (r>b[i].t) dec(a[r--]);
    		while (l<b[i].s) dec(a[l++]);
    		ans[b[i].id]=t[1].a;
    	}
    	for (int i=1;i<=m;++i) printf("%lld
    ",ans[i]);
    }
    
  • 相关阅读:
    数据采集都做不到,怎么谈智能制造?
    值得借鉴的德国制造工厂生产观念!
    APS应用案例|纽威阀门实现高效排产
    MES应用案例|新宏泰电器乘上智能制造的东风
    你的MES今天升级了吗?
    APP-2.1-Hbuilder与夜神 & HbuilderX与夜神模拟器连接
    APP-3-百度地图应用
    APP-2-Hbuilder开发环境搭建
    ABAP-Keyword Documentation
    APP-1-相关介绍及资料
  • 原文地址:https://www.cnblogs.com/owenyu/p/6724686.html
Copyright © 2020-2023  润新知