• Codeforces 575A


    题面传送门

    题意:
    给出 (s_0,s_1,s_2,dots,s_{n-1}),对于 (igeq n),有 (m)(s_i) 满足 (s_i eq s_{imod n}),这 (m)(s_i) 特殊给定,其它的 (s_i=s_{imod n})
    另有序列 (f_i) 满足 (f_0=0,f_1=1)(f_i=f_{i-1}s_{i-1}+f_{i-2}s_{i-2})
    (f_xmod P)
    (1leq n,mleq 5 imes 10^4,0leq xleq 10^{18})

    Fibo纳粹
    粉兔:矩阵快速幂 sb 题。
    我:矩阵快速幂神仙题。
    这好像是上赛季的一个 jxd 作业。
    首先写出矩阵递推式:

    ([f_{i-2},f_{i-1}] imesegin{bmatrix}0&s_{i-2}\1&s_{i-1}end{bmatrix}=[f_{i-1},f_i])

    于是 ([f_{x-1},f_x]=[0,1] imesprodlimits_{i=1}^{x-1}egin{bmatrix}0&s_{i-1}\1&s_{i}end{bmatrix})
    首先考虑 (m=0) 的情况。后面 (prod) 的矩阵成周期性分部。所以可以求出每个周期内所有矩阵的乘积,跑个矩阵快速幂,最后的零头暴力算一下就可以了。
    接下来考虑 (m eq 0) 的情况。记 (P=prodlimits_{i=0}^{n-1}egin{bmatrix}0&s_i\1&s_{(i+1)mod n}end{bmatrix}),不难发现,对于大多数周期,其中所有矩阵的乘积都为 (P),最多只有 (2m) 个周期的乘积 ( eq P)
    故可以对这些特殊的周期特殊计算,其它周期跑矩阵快速幂。
    考虑一个特殊点 (x_i) 会造成什么影响,会使 (x_i)(x_i-1) 的转移矩阵发生变化。
    所以我们对于所有 (x_i)(x_i-1) 所在的周期单独计算它的贡献。
    我们建立 (n) 个矩阵 (A_0,A_1,A_2,dots,A_{n-1}),初始 (A_i=egin{bmatrix}0&s_i\1&s_{(i+1)mod n}end{bmatrix})
    对于某个周期中特殊处理的点 (p),我们修改 (pmod n) 转移矩阵的值,然后求一遍所有 (A_i) 的乘积。处理完这个周期后再改回去。
    于是此题变为:修改某个矩阵的值,求所有矩阵的乘积。
    注意到矩阵是不支持除法操作的,所以这玩意儿只能用线段树维护。
    时间复杂度 (2^3nlog n)
    细节恶心得要死。。。。

    #include <bits/stdc++.h>
    using namespace std;
    #define fi first
    #define se second
    #define fz(i,a,b) for(int i=a;i<=b;i++)
    #define fd(i,a,b) for(int i=a;i>=b;i--)
    #define ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
    #define fill0(a) memset(a,0,sizeof(a))
    #define fill1(a) memset(a,-1,sizeof(a))
    #define fillbig(a) memset(a,63,sizeof(a))
    #define pb push_back
    #define ppb pop_back
    #define mp make_pair
    template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
    template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
    typedef pair<int,int> pii;
    typedef long long ll;
    template<typename T> void read(T &x){
    	char c=getchar();T neg=1;
    	while(!isdigit(c)){if(c=='-') neg=-1;c=getchar();}
    	while(isdigit(c)) x=x*10+c-'0',c=getchar();
    	x*=neg;
    }
    const int MAXN=5e4;
    const int SIZE=2;
    ll x;int mod,n,m,k,b[MAXN+5];
    pair<ll,int> p[MAXN+5];
    ll tk[MAXN*2+5];
    struct mat{
    	int a[SIZE][SIZE];
    	mat(){memset(a,0,sizeof(a));}
    	friend mat operator *(mat x,mat y){
    		mat ret;
    		for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++)
    			ret.a[i][j]=(ret.a[i][j]+1ll*x.a[i][k]*y.a[k][j]%mod)%mod;
    		return ret;
    	}
    };
    struct node{int l,r;mat val;} s[MAXN*4+5];
    void build(int k,int l,int r){
    	s[k].l=l;s[k].r=r;if(l==r) return;
    	int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    }
    void modify(int k,int p,mat x){
    	if(s[k].l==s[k].r){s[k].val=x;return;}
    	int mid=(s[k].l+s[k].r)>>1;
    	if(p<=mid) modify(k<<1,p,x);else modify(k<<1|1,p,x);
    	s[k].val=s[k<<1].val*s[k<<1|1].val;
    }
    mat query(int k,int l,int r){
    	if(l<=s[k].l&&s[k].r<=r) return s[k].val;
    	int mid=(s[k].l+s[k].r)>>1;
    	if(r<=mid) return query(k<<1,l,r);
    	else if(l>mid) return query(k<<1|1,l,r);
    	else return query(k<<1,l,mid)*query(k<<1|1,mid+1,r);
    }
    mat qpow(mat x,ll e){
    	mat ret;ret.a[0][0]=ret.a[1][1]=1;
    	while(e){if(e&1) ret=ret*x;x=x*x;e>>=1;}
    	return ret;
    }
    map<ll,int> mmp;
    signed main(){
    //	freopen("in.txt","r",stdin);
    	scanf("%lld%d%d",&x,&mod,&n);x--;
    	if(x==-1) return printf("0
    "),0;
    	for(int i=0;i<n;i++) scanf("%d",&b[i]);scanf("%d",&m);
    	for(int i=1;i<=m;i++) scanf("%lld%d",&p[i].fi,&p[i].se);
    	for(int i=1;i<=m;i++) mmp[p[i].fi]=p[i].se;
    	for(int i=1;i<=m;i++){
    		tk[++k]=p[i].fi;
    		if(p[i].fi!=n) tk[++k]=p[i].fi-1;
    	}
    	sort(tk+1,tk+k+1);k=unique(tk+1,tk+k+1)-tk-1;build(1,0,n-1);
    	for(int i=0;i<n;i++){
    		mat t;t.a[0][0]=0;t.a[1][0]=1;t.a[0][1]=b[i];
    		if(!mmp[i+1]) t.a[1][1]=b[(i+1)%n];else t.a[1][1]=mmp[i+1];
    		modify(1,i,t);
    	}
    	mat ret;
    	if(x<n) ret=query(1,0,x);
    	else{
    		ret=query(1,0,n-1);
    		if(mmp[n]){
    			mat t;t.a[0][0]=0;t.a[1][0]=1;t.a[0][1]=b[n-1];t.a[1][1]=b[0];
    			modify(1,n-1,t);
    		}
    		int cur=1,pre=0;ll pn=0;bool flg=0;
    		while(cur<=k){
    //			puts("-1");
    //			printf("%d %d %d
    ",cur,pn,pre);
    			if(x/n<tk[pre+1]/n){
    				ret=ret*qpow(query(1,0,n-1),(x/n)-pn-1);
    				ret=ret*query(1,0,x%n);flg=1;break;
    			}
    			ret=ret*qpow(query(1,0,n-1),(tk[pre+1]/n)-pn-1);
    			while(cur<=k&&tk[cur]/n==tk[pre+1]/n){
    				ll id=tk[cur];int v1,v2;
    				if(!mmp[id]) v1=b[id%n];else v1=mmp[id];
    				if(!mmp[id+1]) v2=b[(id+1)%n];else v2=mmp[id+1];
    //				printf("%lld %d %d %d
    ",id,id%n,v1,v2);
    				mat t;t.a[0][0]=0;t.a[1][0]=1;t.a[0][1]=v1;t.a[1][1]=v2;
    				modify(1,id%n,t);cur++;
    			}
    			if((x/n)==(tk[pre+1]/n)){
    				ret=ret*query(1,0,x%n);flg=1;break;
    			} else ret=ret*query(1,0,n-1);
    			for(int i=pre+1;i<cur;i++){
    				mat t;t.a[0][0]=0;t.a[1][0]=1;
    				t.a[0][1]=b[tk[i]%n];t.a[1][1]=b[(tk[i]+1)%n];
    				modify(1,tk[i]%n,t);
    			}
    			pn=tk[pre+1]/n;pre=cur-1;
    		}
    		if(!flg){
    //			puts("-1");
    			ret=ret*qpow(query(1,0,n-1),(x/n)-pn-1);
    			ret=ret*query(1,0,x%n);
    		}
    	}
    	mat f;f.a[0][1]=1;f=f*ret;
    	printf("%d
    ",f.a[0][0]);
    	return 0;
    }
    /*
    3 998244353
    3
    1 2 1
    3
    3 3
    4 6
    10 8
    
    20 998244353
    3
    100 370 250
    5
    7 230
    23 500
    5 480
    15 530
    19 570
    
    100 998244353
    3
    1 2 1
    2
    3 2
    5 1
    
    1000000 998244353
    3
    100 370 250
    5
    7 230
    23 500
    5 480
    15 530
    19 570
    */
    
  • 相关阅读:
    什么是php面向对象及面向对象的三大特性
    php类的定义与实例化方法
    php面向对象之$this->用法简述
    url的主要功能是什么
    PHP字符串比较函数详解
    PHP截取字符串函数substr()函数实例用法详解
    php 读取文件
    php 正则达达示中的模式修正符
    php正则表示中的元字符
    php 正则表达示中的原子
  • 原文地址:https://www.cnblogs.com/ET2006/p/Codeforces-575A.html
Copyright © 2020-2023  润新知