[CF575A]Fibonotci
Posted StaroForgin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF575A]Fibonotci相关的知识,希望对你有一定的参考价值。
Fibonotci
题解
不知道哪种 ** 出题人会将这种难调至死的 **题放到
A
A
A题的位置上。
我相信这种题的做法的做法大家基本上都是很容易想到的,不如说已经很板了。
很明显,我们可以通过矩阵乘法来维护每次转移,就跟普通的,由于它的所有转移式循环的,我们显然只需要维护它
n
n
n这个循环节以内的矩阵的乘积。
上面矩阵的积显然是可以通过线段树来维护的,这样也同时可以支持我们的对矩阵进行实时修改的。
我们可以对于每个涉及到
s
s
s值修改的位置的矩阵进行修改,由于点
i
i
i处的转移矩阵是
{
s
i
−
2
,
s
i
−
1
1
,
0
}
\\left\\{\\begin{array}{c}s_{i-2},s_{i-1}\\\\1,0\\end{array}\\right\\}
{si−2,si−11,0},所以我们修改
s
i
s_{i}
si,要对
i
+
1
i+1
i+1与
i
+
2
i+2
i+2两个位置的矩阵进行修改。
而这个修改还有可能影响的是下一个循环节,还需要特别判断一下。
由于每个循环节的修改都是在最开始的循环节基础上改,我们可以用可持久化线段树来进行维护,这样就不需要刻意去回退了。
对于中间那些不涉及修改的循环节部分我们就可以直接使用矩阵快速幂来进行修改了,直接将最开始的循环节做快速幂乘上去即可。
将每个涉及修改的循环节都枚举一下就行了。
时间复杂度
O
(
w
3
(
n
+
m
(
log
n
+
log
K
)
)
)
O\\left(w^3(n+m(\\log\\,n+\\log\\,K))\\right)
O(w3(n+m(logn+logK)))。
实际上
m
m
m哪里不能说是乘的
l
o
g
K
log\\,K
logK,因为它相当于是一个分段的,或者说是
(
log
K
−
log
m
)
(\\log\\,K-\\log\\,m)
(logK−logm)会好一点。
反正能过就对了。
源码
看起来有点冗长,主要是判所属循环节有点麻烦~~,调了好久~~。
#include<bits/stdc++.h>
using namespace std;
#define MAXN 50005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const int inv2=499122177;
const int jzm=2333;
const int lim=1e9;
const int n1=400;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(LL x,LL y,LL p){return x+y<p?x+y:x+y-p;}
void Add(LL &x,LL y,LL p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int m,root,nrt;LL k,P,val[MAXN],bp[MAXN],n;
struct ming{LL id,v;}p[MAXN];
bool cmp(ming x,ming y){return x.id<y.id;}
struct matrix{
LL c[3][3];matrix(){for(int i=1;i<3;i++)for(int j=1;j<3;j++)c[i][j]=0;}
matrix operator * (const matrix &rhs)const{
matrix res;
for(int i=1;i<3;i++)
for(int k=1;k<3;k++)if(c[i][k])
for(int j=1;j<3;j++)
Add(res.c[i][j],1ll*c[i][k]*rhs.c[k][j]%P,P);
return res;
}
}A;
matrix qkpow(matrix a,LL s){
matrix res;res.c[1][1]=res.c[2][2]=1;
while(s){if(s&1LL)res=res*a;a=a*a;s>>=1LL;}
return res;
}
struct tann{matrix val;int lson,rson;tann(){val=matrix();lson=rson=0;}};
class SegmentTree{
private:
tann tr[MAXN<<3];int tot,lst;
void pushup(int rt){tr[rt].val=tr[tr[rt].lson].val*tr[tr[rt].rson].val;}
public:
void build(int &rt,int l,int r){
if(!rt)rt=lst=++tot;
if(l==r){
tr[rt].val.c[2][1]=1;tr[rt].val.c[2][2]=val[l+1];
tr[rt].val.c[1][2]=val[l];return ;
}
int mid=l+r>>1;
build(tr[rt].lson,l,mid);build(tr[rt].rson,mid+1,r);
pushup(rt);
}
void insert(int &now,int las,int l,int r,int ai){
if(l>r||l>ai||r<ai)return ;int mid=l+r>>1;
if(now==las)tr[now=++tot]=tr[las];
if(l==r){
tr[now].val.c[2][1]=1;tr[now].val.c[2][2]=val[l+1];
tr[now].val.c[1][2]=val[l];return ;
}
if(ai<=mid)insert(tr[now].lson,tr[las].lson,l,mid,ai);
if(ai>mid)insert(tr[now].rson,tr[las].rson,mid+1,r,ai);
pushup(now);
}
matrix query(int rt,int l,int r,int al,int ar){
if(al<=l&&r<=ar)return tr[rt].val;int mid=l+r>>1;
if(ar<=mid)return query(tr[rt].lson,l,mid,al,ar);
if(al>mid)return query(tr[rt].rson,mid+1,r,al,ar);
return query(tr[rt].lson,l,mid,al,ar)*query(tr[rt].rson,mid+1,r,al,ar);
}
void clear(){tot=lst;}
}T;
signed main(){
read(k);read(P);read(n);A.c[1][2]=1;
for(int i=0;i<n;i++)read(val[i]),val[i]%=P;val[n]=val[0];T.build(root,0,n-1);read(m);
for(int i=1;i<=m;i++){read(p[i].id),read(p[i].v);p[i].v%=P;if(p[i].id>=k)i--,m--;}
sort(p+1,p+m+1,cmp);LL las=0;
if(k==0){puts("0");return 0;}
if(k==1){printf("%d\\n",1%P);return 0;}
for(int i=1,j;i<=m;i=j+1){
LL now=(p[i].id+n-1LL)/n;j=i;nrt=root;T.clear();
if(las+1<now)A=A*qkpow(T.query(root,0,n-1,0,n-1),now-las-1LL);
while(j<m&&(p[j+1].id+n-1LL)/n==now)j++;
if(i>1&&p[i-1].id==(now-1)*n){bp[0]=val[0];以上是关于[CF575A]Fibonotci的主要内容,如果未能解决你的问题,请参考以下文章