• CF633H Fibonacciish II 莫队 线段树 矩阵


    CF633H Fibonacci-ish II

    题意很简明 同时给人以不可做感。

    直接暴力大概是\(n^2log\)的 优化一下提前排好序 从小到大枚举数字再枚举询问可以完成\(n^2\)

    经过精细的优化竟然可以过了这个题,可能是出题人没有刻意卡或者根本没想到(赛后hack肯定是有的。

    直接得到一个区间谁也做不了,考虑线段树维护区间 发现也不太能做。

    容易考虑莫队得到每个区间 在加入一个数字的时候 若这个数字不是第一次加入

    带来的影响是比它小的数字不变 后面的统一斐波那契数列向后推一项。

    后者这个操作可以使用矩阵来做多乘以一个矩阵就能完成区间修改。

    删除类似要乘以一个逆矩阵。注意细节。

    关于初始化标记的矩阵最好的初始化为 1001这是单位矩阵,比 0000 的意义更明确。
    在单点修改x的时候查找x的排名省掉一个树状数组或者说线段树上的一次查询。

    pushdown的时候卡卡常不用改变就不改。

    最后一个较为关键的是 莫队的排序 由于莫队指针移动一次的复杂度不是O(1) 所以进行奇偶性优化就很关键,可以省掉一大波常数。

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<cstdio>
    #include<ctime>
    #include<cctype>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 1000000000000000000ll
    #define inf 100000000000000000ll
    #define ldb long double
    #define pb push_back
    #define put_(x) printf("%d ",x);
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define gi(x) scanf("%lf",&x)
    #define put(x) printf("%d\n",x)
    #define putl(x) printf("%lld\n",x)
    #define rep(p,n,i) for(int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define pii pair<int,int>
    #define mk make_pair
    #define P 1000000007ll
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define uint unsigned long long
    #define ui unsigned
    #define EPS 1e-10
    #define sq sqrt
    #define a(x) t[x].a
    #define sum(x) t[x].sum
    #define b(x) t[x].b
    #define max(x,y) ((x)<(y)?y:x)
    using namespace std;
    char *fs,*ft,buf[1<<15];
    inline char gc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        int x=0,f=1;char ch=gc();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
        return x*f;
    }
    const int MAXN=30010;
    int n,m,Q,cnt,S,cc;
    int gg[2][2],kk[2][2];
    int a[MAXN],B[MAXN],c[MAXN],ans[MAXN],w[MAXN],g[MAXN],f[MAXN],v[MAXN];
    inline void 
    struct wy
    {
    	int a,b,sum;
    	int c[2][2];
    }t[MAXN<<2];
    struct jl
    {
    	int l,r;
    	int id;
    }s[MAXN];
    inline int cmp(jl a,jl b){return B[a.l]==B[b.l]?((B[a.l]&1)?a.r>b.r:a.r<b.r):a.l<b.l;}
    inline void discrete()
    {
    	sort(c+1,c+1+n);
    	rep(1,n,i)if(i==1||c[i]!=c[i-1])c[++cnt]=c[i];
    	rep(1,n,i)a[i]=lower_bound(c+1,c+1+cnt,a[i])-c;
    	rep(1,cnt,i)c[i]%=m;
    }
    inline void build(int p,int l,int r)
    {
    	t[p].c[0][0]=t[p].c[1][1]=1;
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	build(p<<1,l,mid);
    	build(p<<1|1,mid+1,r);
    }
    inline void pushdown(int p)
    {
    	if(t[p].c[0][0]==1&&t[p].c[1][1]==1&&t[p].c[1][0]==0&&t[p].c[0][1]==0)return;
    	
    	if(sum(p<<1))
    	{
    		int ww=(a(p<<1)*t[p].c[0][0]+b(p<<1)*t[p].c[1][0])%m;
    		b(p<<1)=(a(p<<1)*t[p].c[0][1]+b(p<<1)*t[p].c[1][1])%m;
    		a(p<<1)=ww;
    	
    	if(t[p<<1].c[0][0]==1&&t[p<<1].c[1][1]==1&&t[p<<1].c[1][0]==0&&t[p<<1].c[0][1]==0)
    		rep(0,1,i)rep(0,1,j)t[p<<1].c[i][j]=t[p].c[i][j];
    	else
    	{
    		rep(0,1,i)rep(0,1,j)kk[i][j]=t[p<<1].c[i][j],t[p<<1].c[i][j]=0;
    		rep(0,1,i)rep(0,1,j)rep(0,1,k)t[p<<1].c[i][j]=(t[p<<1].c[i][j]+kk[i][k]*t[p].c[k][j]);
    		t[p<<1].c[0][0]%=m;
    		t[p<<1].c[1][1]%=m;
    		t[p<<1].c[1][0]%=m;t[p<<1].c[0][1]%=m;
    	}
    	}
    	if(sum(p<<1|1))
    	{
    		int ww=(a(p<<1|1)*t[p].c[0][0]+b(p<<1|1)*t[p].c[1][0])%m;
    		b(p<<1|1)=(a(p<<1|1)*t[p].c[0][1]+b(p<<1|1)*t[p].c[1][1])%m;
    		a(p<<1|1)=ww;
    	
    	if(t[p<<1|1].c[0][0]==1&&t[p<<1|1].c[1][1]==1&&t[p<<1|1].c[1][0]==0&&t[p<<1|1].c[0][1]==0)
    		rep(0,1,i)rep(0,1,j)t[p<<1|1].c[i][j]=t[p].c[i][j];
    	else
    	{
    		rep(0,1,i)rep(0,1,j)kk[i][j]=t[p<<1|1].c[i][j],t[p<<1|1].c[i][j]=0;
    		rep(0,1,i)rep(0,1,j)rep(0,1,k)t[p<<1|1].c[i][j]=(t[p<<1|1].c[i][j]+kk[i][k]*t[p].c[k][j]);
    		t[p<<1|1].c[0][0]%=m;t[p<<1|1].c[1][1]%=m;t[p<<1|1].c[1][0]%=m;t[p<<1|1].c[0][1]%=m;
    	}
    	}
    	t[p].c[0][0]=t[p].c[1][1]=1;t[p].c[1][0]=t[p].c[0][1]=0;
    }
    inline void pushup(int p)
    {
    	a(p)=(a(p<<1)+a(p<<1|1))%m;
    	b(p)=(b(p<<1)+b(p<<1|1))%m;
    	sum(p)=sum(p<<1)+sum(p<<1|1);
    }
    inline void change(int p,int l,int r,int x)
    {
    	if(l==r)
    	{
    		++sum(p);
    		a(p)=c[x]*f[cc]%m;
    		b(p)=c[x]*f[cc-1]%m;
    		return;
    	}
    	pushdown(p);
    	int mid=(l+r)>>1;
    	if(x<=mid)change(p<<1,l,mid,x);
    	else cc+=sum(p<<1),change(p<<1|1,mid+1,r,x);
    	pushup(p);
    }
    inline void change1(int p,int l,int r,int x)
    {
    	if(l==r)
    	{
    		a(p)=b(p)=0;
    		--sum(p);
    		return;
    	}
    	pushdown(p);
    	int mid=(l+r)>>1;
    	if(x<=mid)change1(p<<1,l,mid,x);
    	else change1(p<<1|1,mid+1,r,x);
    	pushup(p);
    }
    inline void modify(int p)
    {
    	int ww=(a(p)*gg[0][0]+b(p)*gg[1][0])%m;
    	b(p)=(a(p)*gg[0][1]+b(p)*gg[1][1])%m;
    	a(p)=ww;
    	
    	rep(0,1,i)rep(0,1,j)kk[i][j]=t[p].c[i][j],t[p].c[i][j]=0;
    	rep(0,1,i)rep(0,1,j)rep(0,1,k)t[p].c[i][j]=(t[p].c[i][j]+kk[i][k]*gg[k][j])%m;
    }
    inline void modify(int p,int l,int r,int L)
    {
    	if(l>=L)
    	{
    		if(sum(p))
    		{
    			gg[0][0]=1;gg[0][1]=1;
    			gg[1][0]=1;gg[1][1]=0;
    			modify(p);
    		}
    		return;
    	}
    	pushdown(p);
    	int mid=(l+r)>>1;
    	if(L<=mid)modify(p<<1,l,mid,L);
    	modify(p<<1|1,mid+1,r,L);
    	pushup(p);
    }
    inline void modify1(int p,int l,int r,int L)
    {
    	if(l>=L)
    	{
    		if(sum(p))
    		{
    			gg[0][0]=0;gg[0][1]=1;
    			gg[1][0]=1;gg[1][1]=m-1;
    			modify(p);
    		}
    		return;
    	}
    	pushdown(p);
    	int mid=(l+r)>>1;
    	if(L<=mid)modify1(p<<1,l,mid,L);
    	modify1(p<<1|1,mid+1,r,L);
    	pushup(p);
    }
    inline void add(int x)
    {
    	if(v[a[x]]==0)
    	{
    		cc=1;change(1,1,cnt,a[x]);
    		if(a[x]+1<=cnt)modify(1,1,cnt,a[x]+1);
    	}
    	++v[a[x]];
    }
    inline void del(int x)
    {
    	if(v[a[x]]==1)
    	{
    		change1(1,1,cnt,a[x]);
    		if(a[x]+1<=cnt)modify1(1,1,cnt,a[x]+1);
    	}
    	--v[a[x]];
    }
    int main()
    {
    	freopen("1.in","r",stdin);
    	n=read();m=read();
    	rep(1,n,i)c[i]=a[i]=read();
    	Q=read();
    	rep(1,Q,i)s[i].l=read(),s[i].r=read(),s[i].id=i;
    	
    	discrete();
    	f[1]=1;
    	rep(2,n,i)f[i]=(f[i-1]+f[i-2])%m;
    	build(1,1,cnt);
    	
    	S=(int)sqrt(n*1.0)+1;
    	rep(1,n,i)B[i]=(i-1)/S;
    	sort(s+1,s+1+Q,cmp);
    	
    	int L=1,R=0;
    	rep(1,Q,i)
    	{
    		while(R<s[i].r)add(++R);
    		while(s[i].l<L)add(--L);
    		while(R>s[i].r)del(R),--R;
    		while(L<s[i].l)del(L),++L;
    		ans[s[i].id]=a(1);
    	}
    	
    	rep(1,Q,i)printf("%d\n",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    自学Java0711
    自学Java0710
    自学Java0709
    自学Java0708
    Leetcode刷题集
    网站收集
    674. 最长连续递增序列『简单』
    680. 验证回文字符串 Ⅱ『简单』
    686. 重复叠加字符串匹配『简单』
    693. 交替位二进制数『简单』
  • 原文地址:https://www.cnblogs.com/chdy/p/16638009.html
Copyright © 2020-2023  润新知