CF633H Fibonacci-ish II 题解
前置知识
解法
考虑莫队,先对原序列进行离散化。
考虑新加入一个数时在权值线段树将后面的数的斐波那契矩阵都乘上一个转移矩阵的系数来表示斐波那契下标加一,删除时将后面的数的斐波那契矩阵都除上一个转移矩阵的系数来表示斐波那契下标减一。
对于常见写法 \(\begin{bmatrix} Fib_{n} & Fib_{n+1} \\ 0 & 0 \end{bmatrix}=\begin{bmatrix} 0 & 1 \\ 0 & 0 \end{bmatrix} \times \begin{bmatrix} 0 & 1 \\ 1 & 1 \end{bmatrix}^{n}\),我们发现 \(\begin{bmatrix} 0 & 1 \\ 0 & 0 \end{bmatrix}\) 没有逆矩阵,只能另行他法尝试删去其中的 \(0\)。
另一种写法是 \(\begin{bmatrix} Fib_{n+1} & Fib_{n} \\ Fib_{n} & Fib_{n-1} \end{bmatrix}=\begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix} \times \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}^{n}\),而 \(\begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}\) 的逆矩阵是它本身,\(\begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}\) 的逆矩阵是 \(\begin{bmatrix} 0 & 1 \\ 1 &-1 \end{bmatrix}\)。这样就解决了乘/除一个系数的问题。
略带卡常。需要取模优化和预处理斐波那契及其逆矩阵。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define sort stable_sort
#define endl '\n'
int a[30010],b[30010],c[30010],pos[30010],L[30010],R[30010],ans[30010],cnt[30010],klen,ksum,p;
struct ask
{
int l,r,id;
}q[30010];
bool q_cmp(ask a,ask b)
{
return (pos[a.l]==pos[b.l])?((pos[a.l]%2==1)?(a.r<b.r):(a.r>b.r)):(a.l<b.l);
}
struct Matrix
{
int ma[4];
Matrix()
{
memset(ma,0,sizeof(ma));
}
Matrix operator + (const Matrix &another)
{
Matrix ans;
ans.ma[0]=(ma[0]+another.ma[0])%p;
ans.ma[1]=(ma[1]+another.ma[1])%p;
ans.ma[2]=(ma[2]+another.ma[2])%p;
ans.ma[3]=(ma[3]+another.ma[3])%p;
return ans;
}
Matrix operator * (const Matrix &another)
{
Matrix ans;
ans.ma[0]=(ma[0]*another.ma[0]+ma[1]*another.ma[2])%p;
ans.ma[1]=(ma[0]*another.ma[1]+ma[1]*another.ma[3])%p;
ans.ma[2]=(ma[2]*another.ma[0]+ma[3]*another.ma[2])%p;
ans.ma[3]=(ma[2]*another.ma[1]+ma[3]*another.ma[3])%p;
return ans;
}
Matrix operator * (const int &another)
{
Matrix ans;
ans.ma[0]=ma[0]*another;
ans.ma[1]=ma[1]*another;
ans.ma[2]=ma[2]*another;
ans.ma[3]=ma[3]*another;
return ans;
}
}Base,invBase,Fib[30010],invFib[30010];
struct SMT
{
struct SegmentTree
{
int val,lazy;
Matrix sum;
}tree[120010];
#define lson(rt) (rt<<1)
#define rson(rt) (rt<<1|1)
void pushup(int rt)
{
tree[rt].sum=(tree[lson(rt)].sum*tree[lson(rt)].val)+(tree[rson(rt)].sum*tree[rson(rt)].val);
}
void build(int rt,int l,int r)
{
if(l==r)
{
tree[rt].val=0;
tree[rt].sum=Base;
return;
}
tree[rt].val=1;
int mid=(l+r)>>1;
build(lson(rt),l,mid);
build(rson(rt),mid+1,r);
}
void pushdown(int rt)
{
if(tree[rt].lazy!=0)
{
if(tree[rt].lazy>0)
{
tree[lson(rt)].sum=tree[lson(rt)].sum*Fib[tree[rt].lazy];
tree[rson(rt)].sum=tree[rson(rt)].sum*Fib[tree[rt].lazy];
}
else
{
tree[lson(rt)].sum=tree[lson(rt)].sum*invFib[-tree[rt].lazy];
tree[rson(rt)].sum=tree[rson(rt)].sum*invFib[-tree[rt].lazy];
}
tree[lson(rt)].lazy+=tree[rt].lazy;
tree[rson(rt)].lazy+=tree[rt].lazy;
tree[rt].lazy=0;
}
}
void update1(int rt,int l,int r,int pos,int val)
{
if(l==r)
{
tree[rt].val=val;
return;
}
pushdown(rt);
int mid=(l+r)>>1;
if(pos<=mid)
{
update1(lson(rt),l,mid,pos,val);
tree[rson(rt)].sum=tree[rson(rt)].sum*Base;
tree[rson(rt)].lazy++;
}
else
{
update1(rson(rt),mid+1,r,pos,val);
}
pushup(rt);
}
void update2(int rt,int l,int r,int pos,int val)
{
if(l==r)
{
tree[rt].val=val;
return;
}
pushdown(rt);
int mid=(l+r)>>1;
if(pos<=mid)
{
update2(lson(rt),l,mid,pos,val);
tree[rson(rt)].sum=tree[rson(rt)].sum*invBase;
tree[rson(rt)].lazy--;
}
else
{
update2(rson(rt),mid+1,r,pos,val);
}
pushup(rt);
}
}T;
void init(int n,int m)
{
klen=n/sqrt(m)+1;
ksum=n/klen;
for(int i=1;i<=ksum;i++)
{
L[i]=R[i-1]+1;
R[i]=R[i-1]+klen;
}
if(R[ksum]<n)
{
ksum++;
L[ksum]=R[ksum-1]+1;
R[ksum]=n;
}
for(int i=1;i<=ksum;i++)
{
for(int j=L[i];j<=R[i];j++)
{
pos[j]=i;
}
}
Base.ma[0]=1; Base.ma[1]=1; Base.ma[2]=1; Base.ma[3]=0;
invBase.ma[0]=0; invBase.ma[1]=1; invBase.ma[2]=1; invBase.ma[3]=p-1;
Fib[0].ma[0]=1; Fib[0].ma[1]=0; Fib[0].ma[2]=0; Fib[0].ma[3]=1;
invFib[0].ma[0]=1;invFib[0].ma[1]=0;invFib[0].ma[2]=0;invFib[0].ma[3]=1;
for(int i=1;i<=n;i++)
{
Fib[i]=Fib[i-1]*Base;
invFib[i]=invFib[i-1]*invBase;
}
T.build(1,1,b[0]);
}
void add(int x)
{
cnt[a[x]]++;
if(cnt[a[x]]==1)
{
T.update1(1,1,b[0],a[x],c[x]);
}
}
void del(int x)
{
cnt[a[x]]--;
if(cnt[a[x]]==0)
{
T.update2(1,1,b[0],a[x],0);
}
}
int main()
{
int n,m,l,r,i;
scanf("%d%d",&n,&p);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
c[i]=a[i]%p;
}
sort(b+1,b+1+n);
b[0]=unique(b+1,b+1+n)-(b+1);
for(i=1;i<=n;i++)
{
a[i]=lower_bound(b+1,b+1+b[0],a[i])-b;
}
scanf("%d",&m);
for(i=1;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
init(n,m);
sort(q+1,q+1+m,q_cmp);
for(i=1,l=1,r=0;i<=m;i++)
{
while(l>q[i].l)
{
l--;
add(l);
}
while(r<q[i].r)
{
r++;
add(r);
}
while(l<q[i].l)
{
del(l);
l++;
}
while(r>q[i].r)
{
del(r);
r--;
}
ans[q[i].id]=T.tree[1].sum.ma[1];
}
for(int i=1;i<=m;i++)
{
printf("%d\n",ans[i]);
}
return 0;
}
本文来自博客园,作者:hzoi_Shadow,原文链接:https://www.cnblogs.com/The-Shadow-Dragon/p/18545913,未经允许严禁转载。
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。